如何将自动生成的 ID 插入关联 table?

How do I insert autogenerated IDs into association table?

我正在尝试编写一个应用程序,从各种烹饪网站上抓取食谱和配料信息。它几乎按照我想要的方式工作,因为我可以成功地将食谱插入食谱 table 并将配料插入配料 table,但我无法填充关联 table.

我的大部分项目都遵循 this tutorial,但它没有演示如何插入关联 table。

我只为 Recipe 创建了一个控制器,其中 Create 函数接受您想要的食谱的 URL。我不想直接从 Ingredient table 操作数据,所以我没有为它创建控制器。

我创建了三个模型 类:食谱、成分和关联 table RecipeIngredient。 Recipe和RecipeIngredient是一对多的关系,Ingredient和RecipeIngredient是一对多的关系。

这些是我的模型:

public class Recipe
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string URL { get; set; }
    public DateTime DateTimeCreated { get; set; }

    public virtual ICollection<RecipeIngredient> RecipeIngredients { get; set; }
}

public class Ingredient
{
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime DateTimeCreated { get; set; }

    public virtual ICollection<RecipeIngredient> RecipeIngredients { get; set; }
}

public class RecipeIngredient
{
    public int ID { get; set; }
    public int RecipeID { get; set; }
    public int IngredientID { get; set; }
    public DateTime DateTimeCreated { get; set; }

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

这是我的 DbContext:

public class RecipeListContext : DbContext
{
    public RecipeListContext() : base("RecipeListContext")
    {
    }

    public DbSet<Recipe> Recipes { get; set; }
    public DbSet<RecipeIngredient> RecipeIngredients { get; set; }
    public DbSet<Ingredient> Ingredients { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

这是来自我的控制器的相关代码:

public class RecipesController : Controller
{
    private RecipeListContext db = new RecipeListContext();

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "URL")] Recipe recipe)
    {
        if (ModelState.IsValid)
        {
            Ingredient ingredient = new Ingredient();
            RecipeIngredient recipeIngredient = new RecipeIngredient();

            var htmlWeb = new HtmlWeb();
            var document = htmlWeb.Load(recipe.URL);

            //This is the route to the recipe and ingredients for 
            //allrecipes.com
            var recipeName = document.DocumentNode.SelectNodes("//h1[@class='recipe-summary__h1']");
            var ingredients = document.DocumentNode.SelectNodes("//span[@itemprop='ingredients']");

            //I populate the Name and DateTimeCreated fields for Recipe here
            recipe.Name = recipeName[0].InnerText;
            recipe.DateTimeCreated = DateTime.Now;

            db.Recipes.Add(recipe);
            db.SaveChanges();

            for (var i = 0; i < ingredients.Count; i++)
            {
                ingredient.Name = ingredients[i].InnerText;
                ingredient.DateTimeCreated = DateTime.Now;
                db.Ingredients.Add(ingredient);
                db.SaveChanges();

                //Here I tried to populate the RecipeIngredient object with 
                //the ID from the Ingredient object, but since that ID gets 
                //created in the database upon insertion, ingredient.ID is 
                //just null. I'm not sure how to access this ID in order to 
                //insert it into RecipeIngredient and I'm not even sure if 
                //this is the right (or best) approach to this problem.

                //recipeIngredient.RecipeID = recipe.ID;
                //recipeIngredient.IngredientID = ingredient.ID;
                //db.RecipeIngredients.Add(recipeIngredient);
                //db.SaveChanges();
            }

            return RedirectToAction("Index");
        }

        return View(recipe);
    }

Entity Framework 中是否有一些功能允许我使用从插入到两个主要 table 中创建的自动生成的 ID 来填充关联 table?或者还有其他解决方案吗?

编辑: 三个问题阻止了我的应用程序按预期工作。

  1. 我需要取消注释将 ingredient.ID 和 recipe.ID 分配给 recipeIngredient 外键的代码。

  2. 我需要在 for 循环内实例化配方和成分对象,以便它们在 for 循环的每次传递开始时重新初始化。我在没有重新初始化它们的情况下收到参照完整性错误。

  3. 我需要填充 recipeIngredients 中的 DateTimeCreated 字段。我忘记这样做了,这导致数据库中出现数据类型不匹配错误,因为空值转换为 01/01/0001 或超出 DateTime 支持的日期范围的类似内容。

我认为 EF 应该使用以下身份更新您的实体对象:

试试这个

db.Recipes.Add(recipe);
db.SaveChanges();
int newPK = recipe.ID;

三个问题导致我的应用程序无法按预期工作。

  1. 我需要取消注释将 ingredient.ID 和 recipe.ID 分配给 recipeIngredient 外键的代码。

  2. 我需要在 for 循环内实例化配方和成分对象,以便它们在 for 循环的每次传递开始时重新初始化。我在没有重新初始化它们的情况下收到参照完整性错误。

  3. 填充 RecipeIngredients 中的 DateTimeCreated 字段,因为我之前忘记这样做了。

我更新后的工作代码如下:

    public ActionResult Create([Bind(Include = "URL")] Recipe recipe)
    {
        if (ModelState.IsValid)
        {
            var htmlWeb = new HtmlWeb();
            var document = htmlWeb.Load(recipe.URL);

            var recipeName = document.DocumentNode.SelectNodes("//h1[@class='recipe-summary__h1']");
            var ingredients = document.DocumentNode.SelectNodes("//span[@itemprop='ingredients']");

            recipe.Name = recipeName[0].InnerText;
            recipe.DateTimeCreated = DateTime.Now;

            db.Recipes.Add(recipe);
            db.SaveChanges();

            for (var i = 0; i < ingredients.Count; i++)
            {
                //Moved these next two lines into the for loop
                Ingredient ingredient = new Ingredient();
                RecipeIngredient recipeIngredient = new RecipeIngredient();

                ingredient.Name = ingredients[i].InnerText;
                ingredient.DateTimeCreated = DateTime.Now;
                db.Ingredients.Add(ingredient);
                db.SaveChanges();

                //uncommented this code
                recipeIngredient.RecipeID = recipe.ID;
                recipeIngredient.IngredientID = ingredient.ID;
                //populated the DateTimeCreated field as I had forgotten
                //to do so already
                recipeIngredient.DateTimeCreated = DateTime.Now;
                db.RecipeIngredients.Add(recipeIngredient);
                db.SaveChanges();
            }

            return RedirectToAction("Index");
        }

        return View(recipe);
    }