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
Related
Using Entity Framework Code first I have a class that holds data for a drop-down list. The same class holds records that are sub-items for the items in the main list. Ultimately this will create a cascading set of drop-down lists.
I am trying to figure out how to make the navigation property for the class link back to itself. The issue class is the one that I am using to populate the drop-down list. The Complaint class also has a link to the Issues class but does not need a link back to the subcategory.
public class Issue
{
public Issue()
{
Complaints = new List<Complaint>();
SubIssues = new List<Issue>();
}
[Key]
public int IssueID { get; set; }
public string Name { get; set; }
public bool IsSubCategory { get; set; }
[ForeignKey("IssueID")]
public ICollection<Issue> SubIssues { get; set; }
public virtual ICollection<Complaint> Complaints { get; set; }
}
public class Complaint
{
public Complaint()
{
}
public int ComplaintID { get; set; }
public string Name {get; set;}
[ForeignKey("IssueID")]
public virtual Issue Issue { get; set; }
}
I did something similar, but actually did only have a parent reference in the children. Either way this should work.
public class Folder
{
[Key]
public int Id { get; set; }
// Some Property
public string Name { get; set; }
// They foreignkey for Many-side
public virtual Folder Parent { get; set; }
// The list for One-side (Not tested in my application)
public virtual ICollection<Folder> SubFolders { get; set; }
}
It is same as a regular one-to-many relation, just all the references are within same entity.
Hello everybody and a happy new 2017,
I have the following table-/object structure.
[Table("Table1")]
public class Table1
{
[Key]
public long Table1Id { get; set; }
public virtual ICollection<Table2> ItemsOfTable2 { get; set; }
}
[Table("Table2")]
public class Table2
{
[Key]
public long Table2Id { get; set; }
public long Table1Id { get; set; }
[ForeignKey("Table1Id")]
public virtual Table1 Table1Object { get; set; }
public virtual ICollection<Table3Base> ItemsOfTable3 { get; set; }
[NotMapped]
public virtual ICollection<Table3Red> RedItems
{
get { return this.ItemsOfTable3.OfType<Table3Red>().ToList(); }
}
[NotMapped]
public virtual ICollection<Table3Blue> BlueItems
{
get { return this.ItemsOfTable3.OfType<Table3Blue>().ToList(); }
}
}
[Table("Table3Base")]
public abstract class Table3Base
{
[Key]
public long Table3Id { get; set; }
public long Table2Id { get; set; }
[ForeignKey("Table2Id")]
public virtual Table2 Table2Object { get; set; }
}
public class Table3Red : Table3Base
{
public string SpecialPropertyForRed { get; set; }
}
public class Table3Blue : Table3Base
{
public int SpecialPropertyForBlue { get; set; }
public virtual ICollection<Table4> ItemsOfTable4 { get; set; }
}
[Table("Table4")]
public class Table4
{
[Key]
public long Table4Id { get; set; }
public long Table3Id { get; set; }
[ForeignKey("Table3Id")]
public virtual Table3Blue Table3BlueObject { get; set; }
}
public class MyContext : DbContext
{
public virtual IDbSet<Table1> Table1DbSet { get; set; }
public virtual IDbSet<Table2> Table2DbSet { get; set; }
public virtual IDbSet<Table3Red> Table3RedDbSet { get; set; }
public virtual IDbSet<Table3Blue> Table3BlueDbSet { get; set; }
public virtual IDbSet<Table4> Table4DbSet { get; set; }
}
So, in the middle of this "tree", there is a TPH structure (classes Table3Base, Table3Red, Table3Blue stored in database table "Table3Base"). And we only have IDbSets for Table3Red and Table3Blue, not for Table3Base. Every object has a collection navigation property of the next table objects.
Class Table3Blue has another collection navigation property to items of Table4 objects.
As further (but hopefully irrelevant) information: The default discriminator is mapped to an internal enum:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
// TPH: Map Standard-Discriminator to Enum
modelBuilder.Entity<Table3Base>()
.Map<Table3Red>(m => m.Requires("Typ").HasValue((int)Table3TypEnum.Red))
.Map<Table3Blue>(m => m.Requires("Typ").HasValue((int)Table3TypEnum.Blue));
}
Due to performance issues (loading every single record one by one is very slow; Lazy Loading is active), we want to read this structure from Table1 to Table4 via include like this:
var table1Records = this.m_Context.Table1DbSet
.Include(t => t.ItemsOfTable2)
.Include(t => t.ItemsOfTable2.Select(t2 => t2.ItemsOfTable3))
.Include(t => t.ItemsOfTable2.Select(t2 => t2.ItemsOfTable3.OfType<Table3Blue>().Select(t3 => t3.ItemsOfTable4)))
.ToList();
The first and the second include seem to work, but the third include throws an Argument exception "The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Parametername: path".
What am I doing wrong? How do I include Table4-objects on my way to the database?
Kind regards, Mate
This is our workaround. I doubt this is the best solution, so better ways are highly appreciated...
Table3Base gets the collection navigation property to Table4 as a virtual property.
Table3Red (the object without Table4-objects) overrides this property with a getter returning an empty list of Table4 objects and no setter.
Therefore, we can cascade our Include down to Table4 without any type checks. There are no unnecessary records in our PTH database table "Table3Base". So everything is fine, except the clumsy definition of Table3Red with an unused navigation property. :-(
BTW: Include with a long path includes all objects along this path, so the explicit ".Include(A).Include(A.B).Include(A.B.C)" is not necessary; ".Include(A.B.C)" will do the same. The iterating .Include in the code sample is for clarity.
HTH, Mate
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 wondering if anyone could advise me on how to accomplish the below using code first in EF6
If I add the Table_3 as a List on to Table_1 & Table_2 in my entities. EF automatically generates a foreign key column for both tables in Table_3 instead of recognizing that they are of the same type.
My model classes are set as follows.
public interface IParent
{
int ID { get; set; }
List<Table_3> Children { get; set; }
}
public class Table_1 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_2 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual IParent Parent { get; set; }
}
EF code first generates the below
Edit
Just to let anyone having the same problems know
I have now resolved this by changing the IParent interface to an abstract class
my classes now look like the following
[Table("ParentBase")]
public abstract class ParentBase
{
[Key]
public int ID { get; set; }
public List<Table_3> Children { get; set; }
}
[Table("Table_1")]
public class Table_1 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_2")]
public class Table_2 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_3")]
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual ParentBase Parent { get; set; }
}
with a table arrangement of
this will work although it would have been nicer if the original could have been met.
I had this problem too, and I used abstract class instead of interface from the beginning.
The problem for mine was my table_3 have two navigation properties:
one is public virtual Table_1, another is public virtual Table_2, and then EF just provisioned these extra foreign key columns,
I merged the two navigation properties into one to
public virtual parentbase {get;set;}. And then it worked. Hope this helps.
Side Note,Would suggest to add virtual keyword on public List Children { get; set; } in parentbase class, because in your previous example , it was already like that.
Thanks for posting this, i came across this issue too.
You can also do like the following where you make a 1 to many relationship between Table_1 and Table_2 with Table_3 respectively:
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
Let me know if anymore clarification is required.
I just started prototyping our existing object model in entity framework/code first and hit my first snag. Unfortunately the documentation for this seems to be very scarce.
My key is not a primitive but an object that wraps a primitive. How do I get this to work with EF/Code first:
public class EFCategoryIdentity
{
public string IdentityValue { get; private set; }
public EFCategoryIdentity(string value)
{
IdentityValue = value;
}
}
public class EFCategory
{
[Key]
public EFCategoryIdentity CategoryIdentity { get; set; }
public string Name { get; set; }
public virtual ICollection<EFProduct> Products { get; set; }
}
public class EFProduct
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
public virtual EFCategory Category { get; set; }
}
What do I need to put here to make this work?
public class MyTestContext : DbContext
{
public DbSet<EFCategory> Categories { get; set; }
public DbSet<EFProduct> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<EFCategory>()
.// Help!
}
}
Thanks!
Entity framework can use only primitive types as keys. Every time you wrap some mapped property to separate type you are creating complex type. Complex types have some limitation
They cannot be keys
They cannot contain keys
They cannot contain navigation properties
etc.