插入一对多记录

时间:2014-12-19 11:09:14

标签: c# asp.net-mvc entity-framework repository

我遇到有关使用实体框架进行插入的问题。

我的应用程序有以下两个实体:

  • 备注
  • 员工

备忘录可以与多名员工联系 员工可以与多个备忘录链接。

这意味着多对多的关系。 我读了一些文章向我解释应该创建一个联结表,我认为这是显而易见的。

文章让我学会了让Entity Framework自动为我创建一个联结表。所以我按照以下方式做到了这一点:

备注

public Guid MemoId { get; set; }
public String Message { get; set; }
public virtual ICollection<Employee> Employees { get; set; }

员工

public Guid EmployeeId { get; set; }
public String Name { get; set; }
public virtual ICollection<Memo> Memos { get; set; }

使用程序包管理器控制台更新数据库时,已在数据库中创建联结表。我使用以下行来做到这一点:
update-database -force -verbose

我有一个创建新备忘录的观点。 可以在此处选择Employees列表并将其添加到备忘录中。 但是,填写此联结表并不按计划进行。我认为它与我的存储库的设置有关。我创建了一个MemoRepository和一个EmployeeRepository。

处理备忘录创建的我的控制器如下:

MemoController

public class MemoController : Controller
{
    private IMemoRepository _memoRepository;
    private IEmployeeRepository _employeeRepository;

    public MemoController(IMemoRepository memoRepository, IEmployeeRepository employeeRepository) {
        _memoRepository = memoRepository;
        _employeeRepository = employeeRepository;
    }

    public ViewResult Create() {
        //Initializes MemoCreateViewModel here
        return View(model);
    }

    [HttpPost]
    public ActionResult Create(MemoCreateViewModel model) {
        if(!ModelState.IsValid)
            return RedirectToAction("Create");

        Guid employeeId;
        List<Guid> employeeIds = new List<Guid>();
        foreach (var id in model.SelectedEmployeeIds) {
            if (!Guid.TryParse(id, out employeeId)) {
                continue;
            }
            employeeIds.Add(employeeId);
        }
        var employees = _employeeRepository.GetEmployeesByIds(employeeIds);
        model.Memo.Employees = employees.ToList<Employee>();
        _memoRepository.SaveMemo(model.Memo);

        return RedirectToAction("List");
    }
}

MemoRepository

public class EFMemoRepository : IMemoRepository
{
    private EFDbContext context;

    public EFMemoRepository(EFDbContext _context) {
        context = _context;
    }

    public IQueriable<Memo> Memos {
        return context.Memos;
    }

    public void SaveMemo(Memo memo) {
        if(memo.MemoId == Guid.Empty) {
            memo.MemoId = Guid.NewGuid();
            context.Memos.Add(memo); //error 1 here 
        } else {
            Memo dbEntry = context.Memos.Find(memo.MemoId);
            if(dbEntry != null) {
                dbEntry.Message = memo.Message;
                dbEntry.Employees = memo.Employees;
            }
        }
    context.SaveChanges(); //error 2 here
    }
}

错误1我在插入时得到:

  

实体对象不能被多个实例引用   IEntityChangeTracker。

错误2我在更新时得到:

  

无法定义两个对象之间的关系,因为   它们附加到不同的ObjectContext对象。

我如何解决这个问题,我阅读的主题是关于人们说它与使用不同的上下文有关,其他人说它与Attach()有关,但我不知道如何在我的内容中解决这个问题。应用

如果您需要更多信息,请告诉我。

注意:我遗漏了一些代码,以便于阅读。如果要求,当然可以添加代码。

1 个答案:

答案 0 :(得分:1)

您收到第一个错误,因为您要添加传递给上下文的Memo对象。但是使用另一个dbContext检索添加到控制器内的memo对象的employee对象。要解决此问题,您必须在两个操作之间共享db上下文,或者必须将Employee对象显式附加到当前上下文。

选项1: 控制器代码

[HttpPost]
public ActionResult Create(MemoCreateViewModel model) {
    if(!ModelState.IsValid)
        return RedirectToAction("Create");

    Guid employeeId;
    List<Guid> employeeIds = new List<Guid>();
    foreach (var id in model.SelectedEmployeeIds) {
        if (!Guid.TryParse(id, out employeeId)) {
            continue;
        }
        employeeIds.Add(employeeId);
    }
    EFDbContext dbContext = new EFDbContext();//Note
    var employees = _employeeRepository.GetEmployeesByIds(dbContext, employeeIds);//Note the extra parameter
    model.Memo.Employees = employees.ToList<Employee>();
    _memoRepository.SaveMemo(dbContext,model.Memo);//Note the extra parameter

    return RedirectToAction("List");
}

EFMemoRepository CLASS CODE:

public void SaveMemo(EFDbContext dbContext, Memo memo) 
{
    if(memo.MemoId == Guid.Empty) 
    {
        memo.MemoId = Guid.NewGuid();
        context.Memos.Add(memo); //error 1 here 
    } else 
    {
        Memo dbEntry = dbContext.Memos.Find(memo.MemoId);
        if(dbEntry != null) 
        {
            dbEntry.Message = memo.Message;
            for (int i = 0; i < dbEntry.Employees.Count; i++)/*Please note that if lazy loading is not True then this reference must explicitly be loaded*/
            {
              dbEntry.Employees.Remove(dbEntry.Employees.First());
            }
            foreach (var item in memo.Employees)
            {
                dbEntry.Employees.Add(item);
            }
           context.Entry(dbEntry).State = EntityState.Modified;                
        }
    }
    dbContext.SaveChanges(); //error 2 here
}

OR

选项2:

public void SaveMemo(Memo memo) 
{
    if(memo.MemoId == Guid.Empty) 
    {
        memo.MemoId = Guid.NewGuid();
        context.Memos.Add(memo); //error 1 here 
    } else 
    {
        Memo dbEntry = context.Memos.Find(memo.MemoId);
        if(dbEntry != null) 
        {
            dbEntry.Message = memo.Message;
            for (int i = 0; i < dbEntry.Employees.Count; i++)/*Please note that if lazy loading is not True then this reference must explicitly be loaded*/
            {
               dbEntry.Employees.Remove(dbEntry.Employees.First());
            }
            foreach (var item in memo.Employees)
            {
                dbEntry.Employees.Add(item);
            }   
            context.Entry(dbEntry).State = EntityState.Modified;              
        }
    }
    context.SaveChanges(); //error 2 here
}

我个人会选择选项1或类似的东西。

如果有什么不清楚就喊出来