简体   繁体   English

Entity Framework Core:同一个对象的多对多关系

[英]Entity Framework Core: many-to-many relationship with the same object

I've started use Entity Framework Core.我已经开始使用 Entity Framework Core。 I have a User entity:我有一个User实体:

public class UserEntity
{
    public UserEntity()
    {
        ForbiddenIngredients = new HashSet<Ingredient>();
        PreferredIngredients = new HashSet<Ingredient>();
    }

    [Key]
    public string ID { get; set; }

    public string Email { get; set; } //UserName
    public string FullName { get; set; }

    public virtual ICollection<Ingredient> ForbiddenIngredients { get; set; }
    public virtual ICollection<Ingredient> PreferredIngredients { get; set; }
}

And I have also Ingredient entity:我还有Ingredient实体:

public class Ingredient
{
    [Key]
    public string IngredientID { get; set; }

    [Required]
    public string Name { get; set; }
}

As you can see, I want to create 2 tables which collect forbidden ingredients and preferred ingredients for each user.如您所见,我想创建 2 个表,为每个用户收集禁用成分首选成分 What should I to to make it work?我应该怎么做才能使它工作?

Your database relationship designing was wrong.你的数据库关系设计是错误的。 You should add more a field to Ingredient to point out Forbidden or Preferred ( tinyint type).您应该向Ingredient添加更多字段以指出ForbiddenPreferredtinyint类型)。

You have to normalize your DB.您必须标准化您的数据库。 The first table keeps a User with a primary key UserId , the second table - Ingridient has IngridientId as a primary key and the third table UserIngridient will keep UserId and Ingridient Id as the foreign keys.第一个表保留一个带有主键 UserId 的用户,第二个表 - Ingridient 将 IngridientId 作为主键,第三个表 UserIngridient 将保留 UserId 和 Ingridient Id 作为外键。 All ingridient are the same, only some of them maybe forbidden for user but it maybe not forbidden for another user .所有成分都是相同的,只有其中一些可能被用户禁止,但可能不会被其他用户禁止。 So you need a forth table - Type.所以你需要第四个表 - 类型。 But since you have only 2 types you can use a flag for this - Forbidden or Prefered.但是由于您只有 2 种类型,因此您可以为此使用标志 - 禁止或首选。 This flag should be kept in UserIngridient Table since it depends on the user and ingridient for this user.此标志应保留在 UserIngridient 表中,因为它取决于用户和该用户的 ingridient。

Change your code to this:将您的代码更改为:

public class User
{
    public User()
    {
        Ingredients = new HashSet<Ingredient>();
       
    }

    [Key]
    public string ID { get; set; }

    public string Email { get; set; } //UserName
    public string FullName { get; set; }

    public virtual ICollection<Ingredient> Ingredients { get; set; }
   
}

public class Ingredient
{
    [Key]
    public int ID { get; set; }

    [Required]
    public string Name { get; set; }
}

And you have to ADD one more table for normalization :并且您必须再添加一张表以进行规范化:

public class UserIngredient
{
    [Key]
    public int ID { get; set; }

     public int UserID { get; set; }
    public int IngredientID { get; set; }
    public int IngredientTypeId { get; set; }  // 0 or 1
   // OR   public string IngredientType { get; set; }   // Forb or Pref
.... add some virtual props  here
}

Answering original question about multiple foreign keys to same table.回答关于同一个表的多个外键的原始问题。 Logic is being set up in DbContext.OnModelConfiguring via Fluent API.正在通过 Fluent API 在DbContext.OnModelConfiguring中设置逻辑。

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace ConsoleApp3
{
    public class User
    {
        public User()
        {
            ForbiddenIngredients = new HashSet<Ingredient>();
            PreferredIngredients = new HashSet<Ingredient>();
        }

        [Key]
        public string ID { get; set; }

        public string Email { get; set; }
        public string FullName { get; set; }

        public virtual ICollection<Ingredient> ForbiddenIngredients { get; set; }
        public virtual ICollection<Ingredient> PreferredIngredients { get; set; }
    }

    public class Ingredient
    {
        [Key]
        public int IngredientID { get; set; }

        [Required]
        public string Name { get; set; }

        public virtual User ForbiddenUser { get; set; }

        public string ForbiddenUserId { get; set; }

        public virtual User PreferredUser { get; set; }

        public string PreferredUserId { get; set; }
    }

    public class AppDbContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Ingredient> Ingredients { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("connection string");
            base.OnConfiguring(optionsBuilder);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>()
                .HasMany(x => x.PreferredIngredients)
                .WithOne(x => x.PreferredUser)
                .HasForeignKey(x => x.PreferredUserId);

            modelBuilder.Entity<User>()
                .HasMany(x => x.ForbiddenIngredients)
                .WithOne(x => x.ForbiddenUser)
                .HasForeignKey(x => x.ForbiddenUserId);

            base.OnModelCreating(modelBuilder);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var user = new User()
            {
                Email = "test@test.com",
                ID = Guid.NewGuid().ToString(),
                FullName = "name",
            };

            user.ForbiddenIngredients.Add(new Ingredient()
            {
                ForbiddenUser = user,
                Name = "forbidden",
            });

            user.PreferredIngredients.Add(new Ingredient()
            {
                PreferredUser = user,
                Name = "preferred",
            });

            var dbContext = new AppDbContext();

            dbContext.Add(user);
            dbContext.SaveChanges();

            var dbUser = dbContext.Users
                .Include(x => x.ForbiddenIngredients)
                .Include(x => x.PreferredIngredients)
                .FirstOrDefault();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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