实体框架4不保存多对多行

时间:2021-10-18 07:41:35

Hopefully a very simple question. But I'm using Code First with an MVC app and I have a Category and ServiceType object that have a many to many relationship:

希望这是一个非常简单的问题。但是我首先使用的是MVC应用程序中的代码我有一个Category和ServiceType对象它们之间有很多很多的关系:

public class Category
{
    public Category()
    {
        ServiceTypes = new HashSet<ServiceType>();
    }

    public Guid CategoryId { get; set; }

    [Required(ErrorMessage = "Name is required")]
    public string Name { get; set; }

    public virtual ICollection<ServiceType> ServiceTypes { get; set; }
}

The database has been generated correctly and contains a linking table called CategoryServiceTypes. My issue is I add items to my ServiceTypes collection and call save and although no error takes place, no rows are added to CategoryServiceTypes. When the below code gets to SaveChanges the count on category.ServiceTypes is 1, so something is definitely in the collection:

数据库已被正确生成,并包含一个名为CategoryServiceTypes的链接表。我的问题是,我将项添加到ServiceTypes集合和调用save,尽管没有发生错误,但是不会向CategoryServiceTypes添加任何行。当下面的代码开始保存时,改变类别的计数。ServiceTypes是1,所以集合中肯定有一些内容:

    [HttpPost]
    public ActionResult Edit(Category category, Guid[] serviceTypeIds)
    {
        if (ModelState.IsValid)
        {
            // Clear existing ServiceTypes
            category.ServiceTypes.Clear();

            // Add checked ServiceTypes
            foreach (Guid serviceType in serviceTypeIds)
            {
                ServiceType st = db.ServiceTypes.Find(serviceType);
                category.ServiceTypes.Add(st);
            }

            db.Entry(category).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(category);
    }

I hope I'm doing something obviously wrong here. Any ideas?

我希望我做错了什么。什么好主意吗?

Thanks.

谢谢。

EDIT:

编辑:

Although the below response is indeed the correct answer I thought I'd add the following final version of the Edit post method:

虽然下面的回答确实是正确的,但我认为我应该添加以下编辑后方法的最终版本:

    [HttpPost]
    public ActionResult Edit(Category category, Guid[] serviceTypeIds)
    {
        if (ModelState.IsValid)
        {
            // Must set to modified or adding child records does not set to modified
            db.Entry(category).State = EntityState.Modified;

            // Force loading of ServiceTypes collection due to lazy loading
            db.Entry(category).Collection(st => st.ServiceTypes).Load(); 

            // Clear existing ServiceTypes
            category.ServiceTypes.Clear();

            // Set checked ServiceTypes
            if (serviceTypeIds != null)
            {
                foreach (Guid serviceType in serviceTypeIds)
                {
                    ServiceType st = db.ServiceTypes.Find(serviceType);
                    category.ServiceTypes.Add(st);
                }
            }

            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(category);
    }

Notice the line that forces the loading of the ServiceTypes collection, this is needed as lazy loading does not include those child items, which means clearing the ServiceTypes collection did nothing.

请注意强制加载ServiceTypes集合的行,这是必需的,因为延迟加载不包括这些子项,这意味着清除ServiceTypes集合什么都没有做。

1 个解决方案

#1


8  

Try to move the line where you attach the category to the context in front of the loop:

试着移动你将类别附加到循环前面上下文的线:

[HttpPost]
public ActionResult Edit(Category category, Guid[] serviceTypeIds)
{
    if (ModelState.IsValid)
    {
        // Clear existing ServiceTypes
        category.ServiceTypes.Clear();
        db.Entry(category).State = EntityState.Modified;
        // category attached now, state Modified

        // Add checked ServiceTypes
        foreach (Guid serviceType in serviceTypeIds)
        {
            ServiceType st = db.ServiceTypes.Find(serviceType);
            // st attached now, state Unchanged
            category.ServiceTypes.Add(st);
            // EF will detect this as a change of category and create SQL
            // to add rows to the link table when you call SaveChanges
        }

        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(category);
}

In your code EF doesn't notice that you have added the servicetypes because you attach the category to the context when the servicetypes are already in the category.ServiceTypes collection and all servicetypes are already attached to the context in state Unchanged.

在您的代码EF中没有注意到您添加了servicetypes,因为当servicetypes已经在类别中时,您将类别附加到上下文。ServiceTypes集合和所有servicetype在状态不变的情况下已经附加到上下文。

#1


8  

Try to move the line where you attach the category to the context in front of the loop:

试着移动你将类别附加到循环前面上下文的线:

[HttpPost]
public ActionResult Edit(Category category, Guid[] serviceTypeIds)
{
    if (ModelState.IsValid)
    {
        // Clear existing ServiceTypes
        category.ServiceTypes.Clear();
        db.Entry(category).State = EntityState.Modified;
        // category attached now, state Modified

        // Add checked ServiceTypes
        foreach (Guid serviceType in serviceTypeIds)
        {
            ServiceType st = db.ServiceTypes.Find(serviceType);
            // st attached now, state Unchanged
            category.ServiceTypes.Add(st);
            // EF will detect this as a change of category and create SQL
            // to add rows to the link table when you call SaveChanges
        }

        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(category);
}

In your code EF doesn't notice that you have added the servicetypes because you attach the category to the context when the servicetypes are already in the category.ServiceTypes collection and all servicetypes are already attached to the context in state Unchanged.

在您的代码EF中没有注意到您添加了servicetypes,因为当servicetypes已经在类别中时,您将类别附加到上下文。ServiceTypes集合和所有servicetype在状态不变的情况下已经附加到上下文。