如何先在代码中保存外键集合

How to save collection of foreign keys in code first

更新: 目前我只能将一种产品分配给 Recipe。我想要做的是在配方(控制器创建)中添加对数据库中所有产品的访问权限 - 这里我使用 public int ProductId 但它只允许保存一个产品。我想从此列表中选择一些产品并将外键保存在数据库中。 photo

我也尝试在 ProductId 中添加 public List < int > 但我从 entity framework.

中收到错误

如有任何帮助,我将不胜感激。

public class Recipe
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public int ProductId { get; set; }

        public List<Product> Products { get; set; }

        public Recipe()
        {
            this.Products = new List<Product>();
        }
    }

    public class Product
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public Recipe? Recipes { get; set; }
    }

如果你想创建一个 one-to-many 关系,你几乎是在正确的方向,但你应该删除 public int ProductId { get; set; } 和 re-arrange,如下例所示。

假设您有以下 类:

    public class Recipe
    {
        [Key]
        public int Id { get; set; }

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

        public List<Product> Products { get; set; } = new();
    }

    public class Product
    {
        [Key]
        public int Id { get; set; }

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

        [Required]
        public Recipe Recipe { get; set; }
    }

您可以如下实例化使用:

    public static void Main()
    {
        var recipe = new Recipe
        {
            Name = "My Recipe",
            Products = new List<Product>
            {
                new Product { Name = "Product 1" },
                new Product { Name = "Product 2" },
                new Product { Name = "Product 3" }
            }
        };

        recipe.Products.ForEach(product =>
        {
            Console.WriteLine(product.Name);
        });
    }

听起来您正在寻找 many-to-many 关系而不是 one-to-many。

如果您使用的是 Code-First 和 EF6 或 EF Core 5+,那么您可以使用:

public class Recipe
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; } = new List<Product>();

}

public class Product
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }

    public virtual ICollection<Recipe> Recipes { get; set; } = new List<Recipe>();
}

要了解幕后发生的事情,EF 应该创建一个名为 ProductRecipe 或 RecipeProduct 的联接 table,其中包含两个 FK。 ProductId 和 RecipeId。这些也将构成本table的复合PK。使用此 table,EF 可以将一种产品关联到多个配方,同时还将一种配方关联到各种产品。在对象模型中,您获得每个配方的产品集合,以及每个产品的配方集合。

对于早期版本的 EF Core,您仅限于必须声明此链接实体,因此您会得到更像的东西:

public class Recipe
{
    // ...

    public virtual ICollection<ProductRecipe> ProductRecipes { get; set; } = new List<ProductRecipe>();

}

public class Product
{
    // ...
    public virtual ICollection<ProductRecipe> ProductRecipes { get; set; } = new List<ProductRecipe>();
}

public class ProductRecipe
{
    [Key, Column(Order = 0)]
    public int ProductId { get; set; }
    [Key, Column(Order = 1)]
    public int RecipeId { get; set; }

    public virtual Product Product { get; set; }
    public virtual Recipe Recipe { get; set; }
}

此方法在其他版本的 EF 中仍然是一个选项,并且是必需的如果您希望支持向连接添加任何其他字段table。例如,如果您想要跟踪 CreatedDate/ModifiedDate 等内容以记录产品何时与食谱相关联等。要通过 EF 将该信息公开给应用程序,EF 需要将 ProductRecipe 作为一个实体了解。权衡的是,当您通常关心配方的产品等时,这种方法会“更混乱”。要获取配方的产品列表,您需要:

var products = context.Products
    .Where(p => p.ProductRecipes.Any(pr => pr.RecipeId == recipeId)
    .ToList();

var products = context.Recipies
    .Where(r => r.RecipeId == recipeId)
    .SelectMany(r => r.ProductRecipies.Select(pr => pr.Product).ToList())
    .ToList();

对比第一种方法中的隐含连接 table:

var produts = context.Recipes
    .Where(r => r.RecipeId == recipeId)
    .SelectMany(r => r.Products)
    .ToList();

...这可以说更容易阅读。