This is how the code looks like:
public class Family
{
public int FamilyID { get; set; }
public virtual ICollection<Member> FamilyMembers { get; set; }
}
public class Member
{
public int MemberID { get; set; }
public virtual Family Family { get; set; }
}
public class Bicycle
{
public int BicycleID { get; set; }
public virtual Member Owner { get; set; }
}
public class MyContext : DbContext
{
public MyContext : base () { }
}
So, there is a one-to-one relantionship between Member and Bicycle, and there is one-to-many relationship between Family and Member.
My question is: how do I initialize these foreign keys using my context? All the tutorials on the internet say how to define, but now how to initialize them. Do I simply assign them a correct int value or do I assign them a whole object, and if so, how do I do that? Using LINQ?
#Edit:
Assume there are 2 families: Smith and Johnson. Smith has 3 members: Ben, Amy, Brian. Johnson has 2 members: John and Natalie. How do I initialize all that in my code?
First, fix this:
public class Member
{
public int MemberID { get; set; }
public virtual Family Family { get; set; }
}
That should be enough to configure the relationships. EF will make the keys identity by convention.
You can assign the relationships multiple ways. You can explicitly set FK Ids if you add them to your models, or you can use the navigation properties like this:
var family = new Family { LastName = "Smith", ...};
List<Member> members = new List<Member>
{
new Member(){ Name = "Ben", ... },
new Member(){ Name = "Amy", ... },
new Member(){ Name = "Brian", ... }
};
family.FamilyMembers = members;
context.Family.Add(family);
context.SaveChanges();
To assign a bike to an owner:
var owner = context.Members.Find(ownerId);
var bike = new Bicycle
{
Make = "ACME",
Model = "XXXX",
Owner = owner
};
context.Bicycles.Add(bike);
context.SaveChanges();
EDIT: Yes, it is certainly permissible to add FK to your model. That's the method I use. Like this code:
public class Member
{
public int MemberID { get; set; }
public int FamilyID { get; set; } // EF will automatically make this a FK by convention
public virtual Family Family { get; set; }
}
You need to add annotations if you don't adhere to convention or if you want them for documentation sake:
public class Member
{
public int MemberID { get; set; }
public int FamilyID { get; set; }
[ForeignKey("FamilyID")]
public virtual Family Family { get; set; }
}
See http://www.entityframeworktutorial.net/code-first/foreignkey-dataannotations-attribute-in-code-first.aspx
I prefer the fluent api. It keeps my models cleaner and separates concerns. For simple projects you can add all the fluent code in the OnModelCreating() override in your context, but I prefer to store my entity configurations in a folder under my context (one file per entity) as described here: http://odetocode.com/blogs/scott/archive/2011/11/28/composing-entity-framework-fluent-configurations.aspx
You can actually have EF automatically find your fluent code using the technique described here: https://msdn.microsoft.com/en-us/magazine/dn519921.aspx
Regarding the child collections, yes, you can new it up in the constructor:
public class Family
{
public Family()
{
FamilyMembers = new HashSet<Member>();
}
public int FamilyID { get; set; }
public virtual ICollection<Member> FamilyMembers { get; set; }
}
You don't need to explicitly define a foreign key between Family and Member. Entity Framework will take care of this for you if you require. Because you have already stated this property
public virtual ICollection<Member> FamilyMembers { get; set; }
On the Family class the Foreign key is created during the initial Add-Migration or Update-database. So you don't need the property
public virtual FamilyFK { get; set; }
Related
I am working on entity framework code first pattern. I have one scenario where i have following entities,
public class Toy
{
public int ID {get; set;}
public string Name {get; set;}
}
for the above entity, all model building configuration has been done and table was created fine.
We have another entity,
public class Kid
{
public string Name {get; set;}
}
For this entity also, all model building configuration has been done and table was craeted fine in database.
Now i need to maintain/configure, one -many relationship between kid and toys i.e. one kid can have multiple toys
so i have create one custom class which will inherit Kid class,
public class KidToy : Kid
{
public virtual List<Toy> Toys{get; set;}
}
Note: I can't add List Toys property directly in Kid class, i am
getting circular refernce error.
builder.Entity<Kid>().Map<KidToy>(m => {
});
builder.Entity<KidToy>().HasMany(b => b.Toys).WithMany().Map(b =>
{
b.MapLeftKey(KidId");
b.MapRightKey("ToyId");
b.ToTable("kidToyMap");
});
I dont need table creation for the custom model class (KidToy) and i need to configure one-many relationship. Could you please guide me.
use this :
public class Toy
{
public int ID { get; set; }
public string Name { get; set; }
public int KidID { get; set; }
[ForeignKey("KidID")]
[InverseProperty("Toys")]
public virtual Kid Kid { get; set; }
}
public class Kid
{
public string Name { get; set; }
[InverseProperty("Kid")]
public virtual ICollection<Toy> Toys { get; set; }
}
So I'm trying to model the following using Entity Framework (code first).
public class School
{
public string Name { get; set; }
public IEnumerable<Class> Classes { get; set; }
}
public class Class
{
public string Name { get; set; }
public TypeOfClass Type { get; set; }
public IEnumerable<Student> Students { get; set; }
}
public enum TypeOfClass
{
Kindergarten,
HighSchool
}
public class Student
{
public string Name { get; set; }
}
public class Kid : Student
{
public string FavouriteToy { get; set; }
}
public class Teenager : Student
{
public int AmountOfAcne { get; set; }
}
I'm wondering how I should model my Entities (and tables) so that I can do something like this to select all Students in the School:
var school = new School();
var kindergartenClass = new Class
{
Name = "Kindergarten",
Type = TypeOfClass.Kindergarten,
Students = new List<Kid>()
};
var highschoolClass = new Class
{
Name = "Kindergarten",
Type = TypeOfClass.HighSchool,
Students = new List<Teenager>()
};
school.Classes = new List<Class> {kindergartenClass, highschoolClass};
IEnumerable<Student> students = school.Classes.SelectMany(x => x.Students);
I wan't to have separate tables for Kids and Teenagers since they have different properties and will only share a subset och common properties.
Anyone with good advice? :)
First off, your classes should have properties that can be recognized by EF as primary keys. Normally these would be non-nullable ints with a name of Id or [ClassName]Id:
public class School
{
public int Id { get; set; } // or SchoolId
}
public class Class
{
public int Id { get; set; } // or ClassId
}
public class Student
{
public int Id { get; set; } // or StudentId
}
You have two options for mapping Kids and Teenagers to separate tables:
Table per Type (TPT) - base class (in this case Student) gets its own table while Kids and Teenagers get one table each with foreign key associations back to the Student table.
Table per Concrete Type (TPC) - Kid and Teenager get their own tables and all the properties from the base class (in this case the Name property from the Student class) get duplicated across all child tables.
I think what you're after is TPC. Also, I think you only want Kids and Teenagers to have tables (not Students). If so, you would need to make the Student class abstract:
public abstract class Student
{
// ...
}
And you would need to override the OnModelCreating method in your context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Kid>().Map(m =>
{
m.ToTable("Kids");
m.MapInheritedProperties();
});
modelBuilder.Entity<Teenager>().Map(m =>
{
m.ToTable("Teenagers");
m.MapInheritedProperties();
});
}
You will need an Id (Key) column. And the navigation properties for collections should be ILIst<>.
public class School
{
// Id and SchoolId are automatically recognized
public int SchoolId { get; set; }
public string Name { get; set; }
// use an IList so that you can Add()
public IList<Class> Classes { get; set; }
}
for the inherited classes you will have to pick a TPC/TPT/TPH model
I'm fairly new to Entity Framework and feel more in control using the Code-First pattern rather than DB-First.
I was wondering what is more preferred when it comes to programmatically setting up ForeignKey relations between the entities.
Is it better to declare a FK_ property in the class which relates to the another class or is it better to declare an IEnumerable<> property in the class that gets related to?
public class IRelateToAnotherClass
{
...
public int FK_IGetRelatedToByAnotherClass_ID { get; set; }
}
or
public class IGetRelatedToByAnotherClass
{
...
public IEnumerable<IRelateToAnotherClass> RelatedTo { get; set; }
}
It all depends on what type of relationships you want between your entities (one-to-one, one-to-many, many-to-many); but, yes, you should declare foreign key properties. Check out this site for some examples.
Here's a one-to-many for your two classes:
public class IRelateToAnotherClass
{
public int Id { get; set; } // primary key
public virtual ICollection<IGetRelatedToByAnotherClass> IGetRelatedToByAnotherClasses { get; set; }
}
public class IGetRelatedToByAnotherClass
{
public int Id { get; set; } // primary key
public int IRelateToAnotherClassId { get; set; } // foreign key
public virtual IRelateToAnotherClass IRelateToAnotherClass { get; set; }
}
and with some Fluent API mapping:
modelBuilder.Entity<IGetRelatedToByAnotherClass>.HasRequired<IRelateToAnotherClass>(p => p.IRelateToAnotherClass).WithMany(p => p.IGetRelatedToByAnotherClasses).HasForeignKey(p => p.Id);
If I understand what you're asking correctly, you'd want both. You want an int FK property and an object property to use as the navigation property.
The end result would look something like this:
public class Employee
{
[Key]
public int EmployeeID { get; set; }
[ForeignKey("Store")]
public int StoreNumber { get; set; }
// Navigation Properties
public virtual Store Store { get; set; }
}
public class Store
{
[Key]
public int StoreNumber { get; set; }
// Navigation Properties
public virtual List<Employee> Employees { get; set; }
}
If you haven't already, take a look at navigation properties and lazy-loading. Note that EF is clever enough to figure out that an int StoreID property corresponds to an object Store property, but if they are named differently (such as without the ID suffix), you must use the [ForeignKey] annotation.
I am apparently having a real devil of a time understanding Entity Framework 6 which I am using with ASP.NET MVC 5.
The core of the matter is that I have a really quite simple data model that is typical of any real world situation where I have various business objects that have other business objects as properties (and of course they child objects may in turn have other child business objects) and also various types of lookup/type data (Country, State/Province, LanguageType, StatusType etc.) and I cannot figure out how to save/update it properly.
I keep going back and forth between two error states:
1) I either run into the situation where saving a parent business object results in unwanted duplicate values being inserted into my lookup/type tables (for example saving a business object that has been assigned an existing LanguageType of 'English' will result in another LanguageType for 'English' being inserted into the LanguageType table), or
2) I use some of the suggestions I've seen here and elsewhere on the net (e.g. Saving Entity causes duplicate insert into lookup data, Prevent Entity Framework to Insert Values for Navigational Properties ) to solve issue 1 and then find myself fighting against this same issue: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key .
I will now provide a few code snippets to help build the picture of what I am trying to do and what I am using to do it. First, an example of the entities involved:
public class Customer : BaseEntity
{
public string Name { get; set; }
[LocalizedDisplayName("Contacts")]
public virtual List Contacts { get; set; }
}
public class Contact : BaseEntity
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public int? LanguageTypeID { get; set; }
[Required]
[ForeignKey("LanguageTypeID")]
public virtual LanguageType Language { get; set; }
}
public class LanguageType : Lookup
{
[LocalizedDisplayName("CultureName")]
public string CultureName { get; set; }
}
public class Lookup : BaseEntity
{
public string DisplayName { get; set; }
public int DisplayOrder { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class BaseEntity
{
public int ID { get; set; }
public DateTime? CreatedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public DateTime? DeletedOn { get; set; }
public bool Deleted { get; set; }
public bool Active { get; set; }
public ApplicationUser CreatedByUser { get; set; }
public ApplicationUser UpdatedByUser { get; set; }
}
In my controller, I have some code like the following:
foreach(Contact contact in lstContacts)
{
customer.Contacts.Add(contact);
}
if (ModelState.IsValid)
{
repository.Add(customer);
}
Let us suppose that each of the contacts has the same LanguageType of 'English' assigned (and in this example it is the fact that I am trying to save multiple contacts that have the same LanguageType that triggers the ObjectStateManager error). Initially, the repository.Add() code just did a context.SaveChanges() which did not work as expected, so now it looks something like this (Entity variable is a Customer):
try
{
if(Entity.Contacts != null)
{
foreach(Contact contact in Entity.Contacts)
{
var entry = this.context.Entry(contact.Language);
var key = contact.Language.ID;
if (entry.State == EntityState.Detached)
{
var currentEntry = this.context.LanguageTypes.Local.SingleOrDefault(l => l.ID == key);
if (currentEntry != null)
{
var attachedEntry = this.context.Entry(currentEntry);
//attachedEntry.CurrentValues.SetValues(entityToUpdate);
attachedEntry.State = EntityState.Unchanged;
}
else
{
this.context.LanguageTypes.Attach(contact.Language);
entry.State = EntityState.Unchanged;
}
}
}
}
context.Customers.Add(Entity);
context.SaveChanges();
}
catch(Exception ex)
{
throw;
}
Is it fundamentally wrong to expect this to have worked? How am I supposed to save and example like this? I have similar problems saving similar object graphs. When I look at tutorials and examples for EF, they are all simple and they all just call SaveChanges() after doing something very similar to what I am doing here.
I've just recently been using the ORM capabilities of ColdFusion (which is hibernate under the covers) and there are would simply load the LanguageType entity, assign it to the Contact entity, save the Contact entity, assign it to the Customer and then save the Customer.
In my mind, this is the most basic of situations and I cannot believe that it has caused me so much pain - I hate to say it, but using plain old ADO.NET (or heaven forbid, ColdFusion which I really don't enjoy) would have been MUCH simpler. So I am missing SOMETHING. I apparently have a key flaw in my understanding/approach to EF and If somebody could help me to make this work as expected and help me to figure out just where my misunderstanding lies, I would greatly appreciate it. I have spend too many hours and hours on this and it is a waste of time - I have/will have countless examples just like this one in the code I am building so I need to adjust my thinking with respect to EF right now so I can be productive and do approach things in the expected way.
Your help will mean so much and I thank you for it!
Let's consider the following object graph in which a teacher instance is the root object,
Teacher --[has many]--> courses
Teacher --[Has One]--> Department
In entity framework's DbContext, each instance of an object has a State indicating whether the object is Added, Modified, Removed or Unchanged. What happens apparently is the following :
Creating the root object for the first time
In this case, in addition to the newly created root object Teacher, ALL the child objects in the graph will have the State Added as well even if they're already created. The solution for this problem is to include the foreign key property for each child element and use it instead, i.e. Teacher.DepartmentId = 3 for example.
Updating the root object and one of its child elements' properties
Suppose you fetch a teacher object from the db, and you change the Teacher.Name property as well as the Teacher.Department.Name property; in this case, only the teacher root object will have the State marked as Modified, the department's State on the other hand remains Unchanged and the modification won't be persisted into DB; Silently without any warning.
EDIT 1
I used your classes as follows and I don't have a problem with persisting the objects :
public class Customer : BaseEntity
{
public string Name { get; set; }
public virtual List<Contact> Contacts { get; set; }
}
public class Contact : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int? LanguageTypeID { get; set; }
public Customer Customer { get; set; }
[ForeignKey("LanguageTypeID")]
public LanguageType Language { get; set; }
}
public class LanguageType : Lookup
{
public string CultureName { get; set; }
}
public class Lookup : BaseEntity
{
public string DisplayName { get; set; }
public int DisplayOrder { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class BaseEntity
{
public int ID { get; set; }
public DateTime? CreatedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public DateTime? DeletedOn { get; set; }
public bool Deleted { get; set; }
public bool Active { get; set; }
public ApplicationUser CreatedByUser { get; set; }
public ApplicationUser UpdatedByUser { get; set; }
}
public class ApplicationUser
{
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
And used the following Context :
public class Context : DbContext
{
public Context() : base("name=CS") { }
public DbSet<Customer> Customers { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<LanguageType> LanguageTypes { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//I'm generating the database using those entities you defined;
//Here we're demanding not add 's' to the end of table names
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Then I created a unit tests class with the following :
[TestMethod]
public void TestMethod1()
{
//our context
var ctx = new Infrastructure.EF.Context();
//our language types
var languageType1 = new LanguageType { ID = 1, Name = "French" };
var languageType2 = new LanguageType { ID = 2, Name = "English" };
ctx.LanguageTypes.AddRange(new LanguageType[] { languageType1, languageType2 });
//persist our language types into db before we continue.
ctx.SaveChanges();
//now we're about to start a new unit of work
var customer = new Customer
{
ID = 1,
Name = "C1",
Contacts = new List<Contact>() //To avoid null exception
};
//notice that we're assigning the id of the language type and not
//an object.
var Contacts = new List<Contact>(new Contact[] {
new Contact{ID=1, Customer = customer, LanguageTypeID=1},
new Contact{ID=2, Customer = customer, LanguageTypeID=2}
});
customer.Contacts.AddRange(Contacts);
//adding the customer here will mark the whole object graph as 'Added'
ctx.Customers.Add(customer);
//The customer & contacts are persisted, and in the DB, the language
//types are not redundant.
ctx.SaveChanges();
}
It all worked smoothly without any problems.
As far as i know there is no build in support for reattaching modified graphs (like the SaveOrUpdate method of nHibernate). Perhaps this or this can help you.
i have 2 entities each with a relating c# class. I set up a navigation property on table A to contain a reference to many items in table B. When i make a new table A class object i need to be able to create the collection of table B objects in table A. How do i set up the navigation property in the table A c# class?
DATAMODEL:
http://bluewolftech.com/mike/mike/datamodel.jpg
Navigation properties are simple in EF. The example below shows how a navigation property would look:
public class Foo
{
public int FooId { get; set; }
public string SomeProperty { get; set; }
public virtual IEnumerable<Bar> Bars { get; set; }
}
Where Foo represents tableA and Bar represents tableB. They key word for the navigation property is virtual which enables lazy-loading by default. This is assuming you're using EF4.1 Code First.
EDIT
Off the top of my head, this should be a good starting template for you:
public class PointOfInterestContext : DbContext
{
public IDbSet<PointOfInterest> PointOfInterest { get; set; }
public IDbSet<POITag> POITag { get; set; }
public IDbSet<Tag> Tag { get; set; }
public override OnModelCreating(DbModelBuilder modelBuilder)
{
// custom mappings go here
base.OnModelCreating(modelBuilder)
}
}
public class PointOfInterest
{
// properties
public int Id { get; set; }
public string Title { get; set; }
// etc...
// navigation properties
public virtual IEnumerable<POITag> POITags { get; set; }
}
public class POITag
{
// properties
public int Id { get; set;}
public int PointOfInterestId { get; set; }
public int TagId { get; set; }
// navigation properties
public virtual PointOfInterest PointOfInterest { get; set; }
public virtual Tag Tag { get; set; }
}
public class Tag
{
// properties
public int Id { get; set; }
public string TagName { get; set; }
// etc...
// navigation properties
public virtual IEnumerable<POITags> POITags { get; set; }
}
Then you would implement the other logic in your business objects. The entities are supposed to be lightweight and at most should have data attributes. I prefer to use the fluent mappings through the OnModelCreating though.
Here are a few good references:
MSDN - EF 4.1 Code First
Code First Tutorial