简体   繁体   中英

ef core 2.1 Many To Many

I have 4 tables, that I'm trying to create in EF Core 2.1, with their relationships

A production has one or more persons in a role. eg A production "Hamilton" has a person in the role of a director,

Production
ProductionId     Name        
------------     -----------
PR1               Hamilton

Person
PersonId         Name
--------         -----------
P1               Rick
P2               Chris
P3               Dan

Role
RoleId           Name
----------       -----------
R1               Director
R2               Choreographer
R3               Actor

ProductionRolePerson
ProductionId    PersonId    RoleId
------------    --------    ------
PR1             P1 (Rick)   R1 (Director)
PR1             P2 (Chris)  R2 (Choreographer)
PR1             P3 (Dan)    R3 (Actor)


Production 
    | 1
    | *
ProductionPersonRole
| *             | *
| 1             | 1
Person         Role

I cant figure out the right way to set up all of the one to many relationships.

Here are the classes I have set up:

 public class Production 
    {
        public int ProductionId { get; set; }
        public List<ProductionPersonRole> Roles { get; set; }
    }

    public class Person 
    {
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public ICollection<ProductionPersonRole> ProductionPersonRoles { get; set; }
    }

public class Role
    {
        public int RoldId { get; set; }
        public string Name {get;set;}
        public ICollection<ProductionPersonRole> Jobs { get; set; }
    }

public class ProductionPersonRole
    {
        public Production Production { get; set; }
        public Person Person { get; set; }
        public Role Role { get; set; }
    }

Here is the DbContext Class:

    public class MyContext : DbContext
        {
            public DbSet<Production> Productions { get; set; }
            public DbSet<ProductionPersonRole> ProductionPersonRoles { get; set; }
            public DbSet<Role> Roles { get; set; }
            public DbSet<Person> Persons { get; set; }

            public MyContext(): base()
            {

            }

            public MyContext(DbContextOptions options): base(options)
            {

            }

            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<ProductionPersonRole>()
                    .HasKey(ppr => new {ppr.Production.ProductionId, ppr.Person.PersonId, ppr.Role.RoldId});

                modelBuilder.Entity<ProductionPersonRole>()
                    .HasOne(ppr => ppr.Production)
                    .WithMany(ppr => ppr.Roles)
                    .HasForeignKey(ppr => ppr.Production.ProductionId);

                modelBuilder.Entity<ProductionPersonRole>()
                    .HasOne(ppr => ppr.Person)
                    .WithMany(ppr => ppr.ProductionPersonRoles)
                    .HasForeignKey(ppr => ppr.Person.PersonId);

                modelBuilder.Entity<ProductionPersonRole>()
                    .HasOne(ppr => ppr.Role)
                    .WithMany(ppr => ppr.Jobs)
                    .HasForeignKey(ppr => ppr.Role.RoleId);

                base.OnModelCreating(modelBuilder);
            }
}

Am I headed in the correct direction?

Yes, just verify the DB architecture. Because if not correct the EF will create DB with different architecture.

The design is ok. But fluent configuration is not. EF Core does not allow using nested properties inside fluent API, so your HasKey and HasForeignKey methods usage will lead to runtime exception.

Since your model conforms to EF Core conventions, and all relationships are described with navigation properties in both ends, EF Core will be able to automatically determine almost everything w/o any fluent configuration, except the join entity composite primary key. It's the only one that requires fluent configuration.

While it's possible to configure the composite PK just with shadow properties (knowing EF Core conventions for FK property naming, for instance public Person Person -> int PersonId ):

modelBuilder.Entity<ProductionPersonRole>()
     .HasKey("ProductionId", "PersonId", "RoleId");

I would recommend adding explicit FK properties to the join entity:

public class ProductionPersonRole
{
    public int ProductionId { get; set; }
    public int PersonId { get; set; }
    public int RoleId { get; set; }
    public Production Production { get; set; }
    public Person Person { get; set; }
    public Role Role { get; set; }
}

and used the following configuration instead:

modelBuilder.Entity<ProductionPersonRole>()
     .HasKey(ppr => new { ppr.ProductionId, ppr.PersonId, ppr.RoleId });

It not only avoid the usage of hardcoded strings, but also could be very helpful when inserting/deleting links in disconnected scenarios.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM