实体框架核心:与同一对象的多对多关系

时间:2020-11-01 11:45:25

标签: .net asp.net-core .net-core entity-framework-core

我已经开始使用Entity Framework Core。我有一个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; }
}

我还有Ingredient实体:

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

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

如您所见,我想创建2个表,为每个用户收集禁用成分首选成分。我应该怎么做才能使其正常工作?

3 个答案:

答案 0 :(得分:1)

您的数据库关系设计错误。您应该向Ingredient添加更多字段以指出ForbiddenPreferredtinyint类型)。

答案 1 :(得分:1)

您必须规范化数据库。第一个表保留一个具有主键UserId的User,第二个表-Ingridient将IngridientId用作主键,第三个表UserIngridient会将UserId和Ingridient Id保留为外键。所有要素都相同,可能其中只有一部分禁止用户使用,但另一名用户则不禁止。因此,您需要第四张表-类型。但是由于只有两种类型,因此可以为此使用标志-禁止或优先。此标志应保留在UserIngridient表中,因为它取决于用户和该用户的本机。

将代码更改为此:

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; }
}

您还必须再添加一张表格进行标准化:

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
}

答案 2 :(得分:0)

回答有关同一表的多个外键的原始问题。正在通过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();
        }
    }
}