Create Direct Navigation Property in EF Core Many to Many Relationship

后端 未结 1 1372
北恋
北恋 2021-01-27 10:06

I\'ve been working through the following tutorial on how to create a many-to-many relationship using Entity Framework Core: https://docs.microsoft.com/en-us/ef/core/modeling/rel

相关标签:
1条回答
  • 2021-01-27 10:47

    In EF6 you would just omit the Linking Entity and EF will create the linking table behind the scenes.

    eg

    public class Group
    {
        public int GroupId { get; set; }
        public string GroupName { get; set;}            
        public virtual List<User> GroupMembers { get; set; } = new List<User>();
    }
    public class User
    {
        public int UserId { get; set; }
        public string Email { get; set; }
        public virtual List<Group> MemberOf {get; set;} = new List<Group>();
    }
    

    But, that doesn't work on EF Core. So let's go around to the workshop and build a workaround.

    One idea is to put a NotMapped property on the entities that gives us the skip-level navigation property, and then ignore the real Navigation Properties in JSON serialization. Also to break the cycles there's a ContractResolver that will skip serialization of the "navigation property" to eliminate cycles in the object graph.

    Like this:

    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Design;
    using Newtonsoft.Json;
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.ComponentModel.DataAnnotations;
    using Newtonsoft.Json.Serialization;
    using System.Reflection;
    
    namespace EFCore2Test
    {
        public class Group
        {
            public int GroupId { get; set; }
            public string GroupName { get; set; }
            [JsonIgnore]
            public virtual ICollection<GroupMember> GroupMembers { get; } = new HashSet<GroupMember>();
    
            [NotMapped]
            public IList<User> Users => GroupMembers.Select(m => m.User).ToList();
        }
    
        public class GroupMember
        {
            public int GroupId { get; set; }
            public Group Group { get; set; }
            public int UserId { get; set; }
            public User User { get; set; }
        }
    
        public class User
        {
    
            public int UserId { get; set; }
            public string Email { get; set; }
    
            [JsonIgnore]
            public virtual ICollection<GroupMember> MemberOf { get; } = new HashSet<GroupMember>();
    
            [NotMapped]
            public IList<Group> Groups => MemberOf.Select(m => m.Group).ToList();
        }
    
        public class Db : DbContext
        {
    
    
            public DbSet<User> Users { get; set; }
            public DbSet<Group> Groups { get; set; }
    
            public DbSet<GroupMember> GroupMembers { get; set; }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<GroupMember>()
                    .HasKey(t => new { t.UserId, t.GroupId });
    
                modelBuilder.Entity<GroupMember>()
                    .HasOne(pt => pt.User)
                    .WithMany(p => p.MemberOf)
                    .HasForeignKey(pt => pt.UserId);
    
                modelBuilder.Entity<GroupMember>()
                    .HasOne(pt => pt.Group)
                    .WithMany(t => t.GroupMembers)
                    .HasForeignKey(pt => pt.GroupId);
            }
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder.UseSqlServer("Server=(local);Database=Test;Trusted_Connection=True;MultipleActiveResultSets=true");
                base.OnConfiguring(optionsBuilder);
            }
        }
    
    
        class Program
        {
    
            public class DontSerialze<T> : DefaultContractResolver
            {
    
    
                protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
                {
    
                    JsonProperty property = base.CreateProperty(member, memberSerialization);
    
                    if (property.PropertyType == typeof(T))
                    {
                        property.ShouldSerialize = o => false;
                    }
    
                    return property;
                }
            }
            static void Main(string[] args)
            {
    
                using (var db = new Db())
                {
                    db.Database.EnsureDeleted();
                    db.Database.EnsureCreated();
    
                    var users = Enumerable.Range(1, 20).Select(i => new User() { Email = $"user{i}@wherever" }).ToList();
    
                    var groups = Enumerable.Range(1, 5).Select(i => new Group() { GroupName = $"group{i}" }).ToList();
    
                    var userGroups = (from u in users from g in groups select new GroupMember() { User = u, Group = g })
                                     .OrderBy(gm => (gm.Group.GroupName + gm.User.Email).GetHashCode())
                                     .Take(100)
                                     .ToList();
    
                    db.Users.AddRange(users);
                    db.Groups.AddRange(groups);
                    db.GroupMembers.AddRange(userGroups);
    
                    db.SaveChanges();
    
                    var ser = new JsonSerializer();
                    ser.Formatting = Formatting.Indented;
                    ser.ContractResolver = new DontSerialze<IList<User>>();
    
                    foreach (var u in users.Take(2))
                    {
                        ser.Serialize(Console.Out, u);
                        Console.WriteLine();
                    }
    
                }
                Console.WriteLine("Hit any key to exit");
                Console.ReadKey();
            }
        }
    }
    

    outputs

    {
      "UserId": 20,
      "Email": "user1@wherever",
      "Groups": [
        {
          "GroupId": 4,
          "GroupName": "group1"
        },
        {
          "GroupId": 2,
          "GroupName": "group3"
        },
        {
          "GroupId": 5,
          "GroupName": "group4"
        },
        {
          "GroupId": 1,
          "GroupName": "group5"
        },
        {
          "GroupId": 3,
          "GroupName": "group2"
        }
      ]
    }
    {
      "UserId": 18,
      "Email": "user2@wherever",
      "Groups": [
        {
          "GroupId": 2,
          "GroupName": "group3"
        },
        {
          "GroupId": 1,
          "GroupName": "group5"
        },
        {
          "GroupId": 5,
          "GroupName": "group4"
        },
        {
          "GroupId": 3,
          "GroupName": "group2"
        },
        {
          "GroupId": 4,
          "GroupName": "group1"
        }
      ]
    }
    Hit any key to exit
    
    0 讨论(0)
提交回复
热议问题