[英]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
添加更多字段以指出Forbidden
或Preferred
( tinyint
类型)。
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.