EF Code First: Many-to-many and one-to-many

前端 未结 2 1546
悲&欢浪女
悲&欢浪女 2021-01-03 00:50

This is probably just because my knowledge with the EF Code First fluent API is lacking, but I\'m stumped.

I want to model the following:

  • A Gro
相关标签:
2条回答
  • 2021-01-03 01:33

    Try this (untested):

    public class Group 
    {
        public int Id { get; set; }
        public string Name { get; set; }
    
        public virtual ICollection<User> PrimaryUsers { get; set; }
        public virtual ICollection<User> SecondaryUsers { get; set; } 
    }
    
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int PrimaryGroupId { get; set; }
    
        public virtual Group PrimaryGroup { get; set; }
        public virtual ICollection<Group> SecondaryGroups { get; set; }
    }
    
    public class Context : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Group> Groups { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            modelBuilder.Entity<User>()
                        .HasRequired(u => u.PrimaryGroup)
                        .WithMany(g => g.PrimaryUsers)
                        .HasForeignKey(u => u.PrimaryGroupId)
                        .WillCascadeOnDelete(false);
    
            modelBuilder.Entity<User>()
                        .HasMany(u => u.SecondaryGroups)
                        .WithMany(g => g.SecondaryUsers)
                        .Map(m => m.MapLeftKey("UserId")
                                   .MapRightKey("GroupId")
                                   .ToTable("SecondaryGroupAssignments"));
        }
    }
    
    0 讨论(0)
  • 2021-01-03 01:33

    Based on Ladislav's excellent answer, here's how to do it without using any mappings - just attributes applied to the Model classes themselves:

    public class Group 
    {
        public int Id { get; set; }
    
        [MaxLength(300)]
        public string Name { get; set; }
    
        public ICollection<User> Users { get; set; }
    }
    
    public class User
    {
        public int Id { get; set; }
    
        [MaxLength(300)]
        public string Name { get; set; }
    
        [ForeignKey("PrimaryGroup")]
        public int PrimaryGroupId { get; set; }
        [Required]
        public Group PrimaryGroup { get; set; }
    
        [InverseProperty("Users")]
        public ICollection<Group> SecondaryGroups { get; set; }
    }
    

    Notes

    If you want, you can add the virtual keyword to the 2 ICollections and the Group. This allows lazy-loading. Performance-wise, I don't recommend it, but it is possible.

    I included MaxLength attributes with an arbitrary (but safe) length of 300, because putting strings out in EF without a MaxLength gets you low-performance NVarChar(MAX) columns. Totally irrelevant to what's being asked but better to post good code.

    I recommend against class names "User" and "Group" for your EF classes. They're going to complicate any SQL you attempt to run later, having to type [User] and [Group] to access them, and complicate using these classes in MVC Controllers where your class User will conflict with the Context property User that gives you access to the Asp.Net Identity library.

    0 讨论(0)
提交回复
热议问题