I inherited a project with all the one to many relationships created in this fashion
[Table("A")]
public partial class A
{
public int Id { get; set; }
public int Something {get; set; }
public virtual ICollection<B> B { get; set; }
}
[Table("B")]
public partial class B
{
[Key]
public int Id { get; set; }
public int Something {get; set; }
[Required]
public virtual A A { get; set; }
}
What struck me was the lack of a int Foreign Key property in the B model.
Entity Framework must create it because they exist in our database.
Can anyone explain first why this is happening and two if this can cause problems with lazy loading?
EntityFramework by default looks for the name "id" and makes it a key. You could specify the decoration to make it faster, since it does not have to guess the key of the table.
I don't believe it affects lazy loading since lazy loading is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook
Sources:
Microsoft Key
Microsoft Lazy Loading
Foreign key properties are not required by the EF. EF can build hidden fields basing on object relations (and I usually use this configuration because I think is more POCO). The only issue is that in some cases, the exception raised during validation or SaveChanges is more cryptic, otherwise everything works fine.
About foreign key column names, you can configure them using fluent api (Map + MapLeftKey, MapRightKey and MapKey methods).
Related
I'm having a hard time defining the relations I want using EF Core(1 to many) .
E.G:
I am an entity of Task and Employee , each task is given by an employee and also is appointed to an employee . I've created the Task class as follow:
public class Task
{
public int TaskId { get; set; }
[ForeignKey("RequestedBy")]
[Required]
public int RequestedById { get; set; }
[Required]
[ForeignKey("TaskedTo")]
public int TaskedToId { get; set; }
public virtual Employee RequestedBy { get; set; }
public virtual Employee TaskedTo { get; set; }
}
I think I've done it correctly, but I have a problem with my Employee class. Usually (When there's only one join) I would simply create virtual collection of Task Property in Employee .. but what am I supposed to do now ? Is this enough to set the relation or should I add virtual properties for these two tasks?
And another thing, when I have an owned entity, with 1-Many relation , is it enough to add the property in the owner entity, and do nothing in the owned one? Or do I have to specify the [Owned] Annotation?
The issue is that you have two one-to-many relationships between the same two entities. For the Employee class you would need two collections, one for each relationship. Additionally, you'll need to use the InverseProperty attribute to tell EF which foreign key goes with which collection:
public class Employee
{
...
[InverseProperty(nameof(Task.RequestedBy))]
public ICollection<Task> RequestedTasks { get; set; }
[InverseProperty(nameof(Task.TaskedTo))]
public ICollection<Task> AssignedTasks { get; set; }
}
You don't need virtual. That's to enable lazy-loading. For the lazy-loading functionality, EF creates a dynamic proxy class that inherits from your entity and overrides the getter on the navigation property. The virtual keyword is required in C# to allow a class member to be overridden.
Also, the Owned attribute is for value objects. It's a way of having a related class whose properties are literally mapped onto the same table or if given its own table, inherently tied to the entity that "owns" it, such that you access that data through the entity, not separately. Neither of which applies here.
Finally, you should reconsider the name Task for this class. .NET already has a Task class, and it's used very frequently. If you name your class Task as well, you'll be having to specify namespaces virtually every time you use either one, which is a pain.
Given the following SQL tables:
EntityGroup:
Id int, (PK)
GroupName nvarchar(100)
Entity:
Id int, (PK)
EntityGroupId int, (FK Non-nullable)
Description nvarchar(100)
And the following POCOs
public class Entity
{
public int Id { get; set; }
public int EntityGroupId { get; set; }
public int RefNumber { get; set; }
}
public class EntityGroup
{
public int Id { get; set; }
public virtual IList<Entity> Entities { get; set; }
}
How do I configure the fluent mapping correctly? I want Entity.EntityGroupId to remain as an int rather than an EntityGroup object.
I want to be able to .Include() optionally Include("Entities"). The closest I got is this, but that seems to eager-load all entities even if I dont use .Include("Entities"), which is not the behaviour I want:
modelBuilder.Entity<EntityGroup>()
.HasMany(x => x.Entities);
You must set off the lazy loading,
you can do this for just a specific unit of work or for all by setting your dbContext Like
dbContext.Configuration.LazyLoadingEnabled = false;
dbContext.Configuration.ProxyCreationEnabled = false;
or set it in Ctor of your DbContext.
The way I understand it, you want to configure one-to-many relationship between EntityGroup and Entity without navigation property in Entity class and using Entity.EntityGroupId as a FK. All that with Fluent API.
It's possible, but you have to start the configuration from the class having a navigation property (EntityGroup in your case) because Has methods require property accessor while With methods have parameterless overloads. As usual, for the last part you will use the HasForeignKey method:
modelBuilder.Entity<EntityGroup>()
.HasMany(e => e.Entities)
.WithRequired()
.HasForeignKey(e => e.EntityGroupId);
But note that EF recognizes the naming convention used in your sample classes (in particular the EntityGroupId), so you'll get the same mapping w/o any fluent configuration or data annotations.
The problem is lazy loading is enabled by default, so it will load the related entities every time you try to get access to them.Two options to solve your issue could be:
Disabling lazy loading in your context:
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
Removing virtual from your navigation property, which is one of
the requirements to work lazy loading and the tracking change:
public ICollection<Entity> Entities { get; set; }
If you want to learn more about the supported ways you can load related entities in EF I suggest you to read this article
I'm trying to understand what I need to do in order to introduce the same Foreign Key in multiple derived classes when the Foreign Key is not present in the base class. The Foreign Key is to the same type, and I'm able to make the various derived classes all use the same column name, but when I try to introduce the Foreign Key annotation, Entity Framework 6 silently fails to create any Foreign Key at all.
It's worth mentioning that, if I allow EF to create Bar_Name1 instead of reusing the existing column, it adds the Foreign Key appropriately. But I come from a relational database background, and it offends my sensibilities to have multiple columns for the same thing.
I would prefer to be able to stick to using Annotations to mark up my code, but if this is something that can't be done with Annotations but can be done with the Fluent API, I'm willing to delve into that.
public class Foo
{
[Key]
public string Name { get; set; }
}
public class FooSub1 : Foo
{
[Required, Column("Bar_Name")]
public string Bar_Name { get; set; }
[ForeignKey("Bar_Name")]
public Bar Bar { get; set; }
}
public class FooSub2 : Foo
{
[Required, Column("Bar_Name")]
public string Bar_Name { get; set; }
[ForeignKey("Bar_Name")]
public Bar Bar { get; set; }
}
public class Bar
{
[Key]
public string Name { get; set; }
}
The resolution to EF issue 1964 explains: "However, having an association in s-space here doesn't work anyway because it results in two database constraints which can only be satisfied if the dependent also matches the PK for the other relationship type. Such a match would usually only happen accidentally. The solution is to remove the associations from s-space like we do for similar TPC mappings." (emphasis mine)
EF drops the FK's on the merged column. In your case, the two FK's are logically the same, but EF doesn't know (or care about) that.
I'm experimenting with EF5 Code First and I am using the models (show below).
When I look at the database that is created, I am confused because I do not see anything in the Track table that points to the Category table. Category has a FK pointing back to Track but that means that there are going to be duplicates of the categories?
A little background: I am trying to build a model that has tracks and every track can have 1 to N Categories. All of the categories are already defined, that is they are basically a lookup and I plan to create them in the seed method when database is created.
I think I am not understanding something obvious... When I query a track, how will I know what category it contains?
Thx
public class Track : IAuditInfo
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public String Data { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public ICollection<Category> Categories { get; set; }
public Track()
{
Categories = new List<Category>();
}
}
public class Category
{
public Int32 Id { get; set; }
public Boolean IsVisible { get; set; }
public String DisplayName { get; set; }
}
Your current model is a one-to-many relationship between tracks and categories.
This usually implemented, as you have noted that entity framework does, using a foreign key on the many side (category) to the one side (track).
If I understand you correctly, what you want is a many-to-many relationship. Many tracks can be related to the same category, and a single track can belong to many categories.
To let entity framework understand that you want a many-to-many relationship you can simply add a ICollection property to your category class.
So both your classes should have a collection of the other class.
I.e. tracks have many categories and categories have many tracks.
For more information you can also see: http://msdn.microsoft.com/en-us/data/hh134698.a.nospx
Olav is right, your data model at the moment is not telling Entity Framework that there is a many-to-many relationship in there.
The simplest way to resolve this is to add
public virtual ICollection<Track> Tracks { get; set; }
to your Category class.
However... You may not want to pollute your domain model with artefacts that are not relevant to your domain. More importantly, when you do it this way, it is up to Entity Framework to figure out what to call the binding table. Prior to EF6 this naming is non deterministic (see http://entityframework.codeplex.com/workitem/1677), which may mean that two different machines compiling the same code will decide on different names for that table and cause some interesting migration problems in your production system.
The answer to both problems is to always explicitly manage many-to-many relationships with Fluent Configuration.
In your Data Context class, override the OnModelCreating, something like this:
public class MyDb : DbContext
{
public IDbSet<Track> Tracks { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Track>()
.HasMany(t => t.Categories)
.WithMany()
.Map(c => c.ToTable("CategoriesForTracks"));
}
}
If you do this, you don't need to add a navigation property to your Category class, though you still can (if you do, you should use the overload for WithMany that allows you to specify a property).
Relationships between entities and how to map that to a relational database is inherently hard. For anything other than the simplest parent-child relationships you will want to use the fluent API to make sure you actually get what you want.
Morteza Manavi has a really good blog series describing relationships in EF Code First in exhaustive detail.
NOTE
You should usually make navigation properties virtual. So, you should change your Category class like this:
public virtual ICollection<Category> Categories { get; set; }
In theory, not making it virtual should just cause eager loading rather than lazy loading to happen. In practice I have always found lots of subtle bugs appearing when my navigation properties are not virtual.
I have two tables in a database. One is for a member and one is for a client. The client table has two columns for who created the row, and who has modified the row. Foreign keys were set up from each column to map back to the member table. All of this makes sense until
one runs Entity Framework against the database and I get the following code generated for me.
public Member()
{
public virtual ICollection<Client> Clients { get; set; }
public virtual ICollection<Client> Clients1 { get; set; }
}
public Client()
{
public virtual Member MemberForCreated { get; set; }
public virtual Member MemberForModified { get; set; }
}
My question is why would Entity Framework think to make a backing collection in the member table for each foreign key relationship to the client table? Do I really need this relationship or is this something that I can remove? Any information would be useful.
As a side note: These collections and relationships are found in the .edmx file under the navigation properties collection of the entities.
EF relationships are bidirectional by default. You can remove either direction if you don't need it.
You can also rename them. You might, e.g., want to call them Member.ClientsCreated and Member.ClientsModified.
Julie Lerman has a video examining unidirectional relationships.