I would like to shift from the common pattern in many to may relation using implicit joint table and instead I want to use the joint table explicitely and implement a kind of lazy load of many-to-many dependent entity.
This is framed by the design of disconnected sets, where the objects graph is passed via http to the application server. On the server I update just keys, not entities.
The reason for that: if I try to save the same entity defined with different instances of an entity model, I get the concurrent scenario error.
Instead, I don't want to pass on object, rather I just want to pass the joint table with IDs.
Class
-------
int ID
List ClassStudent
Student
-------
int ID
List ClassStudent
ClassStudent // this type must be explicitely defined in the model
--------------
StudentID
ClassID
Is it possible to define such configuration with FluentApi?
The common scenarion is using types:
Student
---------------
int ID
List Classes
Class
----------
int ID
List Students
I don't need this beacuse of concurrent changes.
Need to help with fluent API. I've tried many cases.
Yes, it's possible. All you need is to configure a composite PK for the ClassStudent and two unidirectional one-to-many relationships (Student -> ClassStudent and Class -> ClassStudent).
Something like this:
modelBuilder.Entity<ClassStudent>()
.HasKey(e => new { e.StudentID, e.ClassID });
modelBuilder.Entity<Student>()
.HasMany(e => e.ClassStudent)
.WithRequired()
.HasForeignKey(e => e.StudentID);
modelBuilder.Entity<Class>()
.HasMany(e => e.ClassStudent)
.WithRequired()
.HasForeignKey(e => e.ClassID);
Related
I have a Person class which can have Relatives which is a self reference many-to-many relationship(Relative is also a Person). I wanted to maintain this Person->Relatives mapping in a separate table. So, to create this relationship in EF, I did this:
modelBuilder.Entity<Person>()
.HasMany(e => e.Relatives)
.WithMany()
.Map(c =>
{
c.MapLeftKey("PersonId");
c.MapRightKey("RelativeId");
c.ToTable("PersonRelative");
});
Now, this created a new table PersonRelative with two columns PersonId and RelativeId automatically as I planned. It also have composite primary key on PersonId and RelativeId.
Now, there're two things I wish to do here:
I want to add a new identity "Id" column in this new PersonRelative table for better performance. How can I do that?
Now, can I create a separate class for PersonRelative table, the way we have a class for every table. Because that would try creating the table again. So, I think I can either keep that fluent api mapping or the PersonRelative class. Is this correct?
I would really appreciate any help here.
you can achieve two points by the following code:
modelBuilder.Entity<PersonRelative>().HasKey(x => x.Id);
modelBuilder.Entity<PersonRelative>()
.HasOne<Person>(x => x.Person)
.WithMany(s => s.PersonRelative)
.HasForeignKey(x => x.PersonId);
modelBuilder.Entity<PersonRelative>()
.HasOne<Realtive>(x => x.Realtive)
.WithMany(s => s.PersonRelative)
.HasForeignKey(x => x.RelativeId);
it's how to make many-to-many relation in entity framework core, as it's not supported yet in core, you can use it in non-core entity framework too.
Please Note, if you want a new table mapping just for accessing data with navigation properties, then you can add property of type "ICollection" for Students in Relative Class, and the same for Student Class you can add ICollection for access Relatives from Student
I'm creating the entity relationships using Code First with EF Fluent API following the instructions from this tutorial to create the 1:n and m:n relationships in my model.
What I'm wondering and haven't found a response searching, is that if it's required to define the relationship on both ends of it.
By that I mean, if I have an entity called User and Organization, there are two relationships involving these two entities as I described below:
An User can many Organizations, while an Organization must be owned by one User.
An User may be present in many Organizations, while an Organization may have many Users in it.
With this in mind, I defined the relationships using Fluent API as follows:
modelBuilder.Entity<Organization>().HasRequired(o => o.Owner).WithMany(u => u.OrganizationsOwned).WillCascadeOnDelete(false);
modelBuilder.Entity<User>().HasMany<Organization>(u => u.Organizations).WithMany(o => o.Users).Map(uo =>
{
uo.MapLeftKey("UserId");
uo.MapRightKey("OrganizationId");
uo.ToTable("OrganizationsUsers");
});
But are these definitions enough? Or do I have to define the relationships on the other end of the entities too? What I mean, do I need to add the following code?
modelBuilder.Entity<User>().HasMany(u => u.OrganizationsOwned).WithRequired(o => o.Owner).WillCascadeOnDelete(false);
modelBuilder.Entity<Organization>().HasMany<User>(o => o.Users).WithMany(u => u.Organizations).Map(ou =>
{
ou.MapLeftKey("UserId");
ou.MapRightKey("OrganizationId");
ou.ToTable("OrganizationsUsers");
});
Yes, these definitions are enough. You are defining both sides of the relationship with the single statement:
.Entity<Organization>().HasRequired(o => o.Owner).WithMany(u => u.OrganizationsOwned)
The .HasRequired defines the 1 side, and the .WithMany defines the Many side. There is only one relationship, but two sides. You can define the relationship from either side, but you do not have to define it from both.
i have 3 table. 2 of them has got many to many relations. Last one is secondary table like that:
Student:
id------- Name------- SurName
1-------- fsfsf---------- fsfsfsdf
2-------- dfdsf -------- sfsfsdfsdf
Course
id----------Name-------
11-------- course1----------
22-------- course2--------
23-------- course3--------
StudentCourse
Studentid---------CourseId
1-------------------11
1-------------------12
2-------------------22
2-------------------23
2-------------------11
But Secondary table is hidden inside of the Entity framework model. But i need to add Studentid and Courseid without any changes of Course and Student table. How can i achive that?
You can use Fluent-API to map your relation table. To achieve that, you have to edit the OnModelCreating method like this:
modelBuilder.Entity<Course>()
.HasMany<Student>(c => c.Students)
.WithMany(s => s.Courses)
.Map(m => {
m.ToTable("StudentCourses");
m.MapLeftKey("CourseId");
m.MapRightKey("StudentId");
});
Don't forget to do an "update-database" command on your Package Manager.
I have a table of Recipes. Each Recipe has one and only one row in table RecipeMetadata, which contains various data about the recipe that I don't want to store in the Recipes table for various reasons. Thus, Recipes and RecipeMetadata have a one-to-one mapping. My Recipes table is as follows:
public partial class RecipesMap : ClassMap<Recipes>
{
public RecipesMap()
{
Id(x => x.RecipeId);
// Map() various columns here
HasMany(x => x.Ingredients).KeyColumn("RecipeId");
HasOne(x => x.Metadata);
}
}
And here's my RecipeMetadata table:
public partial class RecipeMetadataMap : ClassMap<RecipeMetadata>
{
public RecipeMetadataMap()
{
Id(x => x.RecipeMetadataId);
// Map() various columns here
References<Recipes>(x => x.Recipe).Column("RecipeId").Not.Nullable();
}
}
However, when I load a Recipe and access the Metadata property, it attempts to find a row in RecipeMetadata where Recipes.RecipeId = RecipeMetadata.RecipeMetadataId. In other words, it does the join using the primary keys on both tables.
With my table schema, RecipeMetadataId is a key unique only to that table, and has nothing to do with RecipeId. RecipeMetadata has another column, also called RecipeId which has a foreign key constraint on `Recipes. The JOIN should work as:
Recipes.RecipeId = RecipeMetadata.RecipeId
My Questions:
Am I wrong for wanting RecipeMetadata to have its own unique ID, and to use a separate column to link this to Recipes? Obviously, I have a FK constraint as well as a unique index on RecipeMetadata.RecipeId so there's no perf impact. Yes, there's some extra bytes on the disk for storing an arguably unnecessary ID on this table.
I've never seen a table whose primary key also has a foreign key constraint on another table. Is this legit practice? It seems to be the way nHibernate prefers to behave by default. Should I give in and let it have its way?
Provided I don't want to change the database (Though I can be convinced to do so if given a legitimate reason), how can I create the desired one-to-one mapping with this model?
NHibernate has a strict definition of one-to-one relationships. Strict but fair. In NHibernate one-to-one relationship means that the a row in table A always has a matching row in table B.
Right or wrong, that won't work with NHibernate's one-to-one mapping. Note that the model you propose is identical to how a one-to-many relationship would be modeled.
It's legit and enforces the one-to-one relationship.
Since you want the recipe to always have an associated metadata row, I would model it using NHibernate's one-to-one mapping. Alternatively, you can map it as one-to-many but only expose one instance as a property.
See also: Ayende's post on the topic.
i have two tables:
Components
ComponentDependencies
ComponentDependencies has two columns: ComponentId and ComponentDependencyID. (both foreign keys into Id field of Component table.
i am using fluent nhiberate and i have my component object having:
public virtual IList<ComponentDependency> Dependencies { get; set; }
and in my ComponentMap class, i have nhibernate map:
HasMany(x => x.Dependencies)
.AsBag().Inverse();
So when i have a component object, i can see a list of its dependencies.
Is there anyway i can have an additional property have the "reverse" list. What i mean is that i want a property called "DependentOf" which is also a
IList<ComponentDependency>
which has all of the items where this current component is the dependent component in the relationship?
This looks like a bill-of-materials problem with Components having a many-to-many relationship to itself through the ComponentDependencies linking table. You can map both relationship directions by alternating which column is the parent key column:
HasManyToMany(x => x.Dependencies).Table("ComponentDependencies")
.ParentKeyColumn("ComponentId").ChildKeyColumn("ComponentDependencyId");
HasManyToMany(x => x.DependentOf).Table("ComponentDependencies")
.ParentKeyColumn("ComponentDependencyId").ChildKeyColumn("ComponentId");