2014-12-19 169 views
3

我正面临有关使用实体框架插入的问题。插入一条到多条记录

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

  • 备注
  • 员工

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

这意味着多对多的关系。 我读了几篇文章解释我应该创建一个联结表,我认为这很明显。

这篇文章学会了让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

我有用于创建新备忘录的视图。 可以在这里选择员工列表并将其添加到备忘录中。 但填写此交接表格不按计划进行。我认为这与我的存储库的设置有关。我创建了一个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(),但我不知道怎么我的应用程序内解决此。

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

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

+0

你为什么要使用这种方法目前还不清楚?你不可能首先用所需的联结表和外键创建数据库,然后从中创建模型。这样就容易多了。我个人更喜欢这种方式,因为从代码中更改数据库设计并不总是从数据库的角度来看最好的方法。除非它是遗留系统或业务需求。 – 2014-12-19 11:35:40

+0

@TolgaEvcimen我的大学更喜欢这种方式,我并不介意先使用代码。然而,它应该有可能使用代码的第一种方式.. – Max 2014-12-19 11:38:31

+0

是的你是对的,但是当你正在进入一个方向,不会给你任何杠杆,但你的头靠在墙上,如果你知道存在替代(不解决方法)的方式,而不是那么有效,是吗? – 2014-12-19 12:13:12

回答

1

由于您正在添加传递到上下文的Memo对象,因此您正在收到第1个错误。但是,使用另一个dbContext检索了添加到控制器内备忘对象的员工对象。为了解决这个问题,你必须在两个操作之间共享数据库上下文,或者你必须显式地将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类代码:

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 
} 

我个人WOU ld和选项1一起或者沿着这些线。

怒吼如果有什么

+0

插入工作:)但更新没有将记录添加到名为MemoEmployees的联结表中。可能是什么问题呢? – Max 2014-12-19 12:49:18

+0

是的。要使用相同的方法进行更新,您必须删除所有以前的员工关系并再次添加。这样你将删除不再有效的关系并添加新创建的关系 – Van 2014-12-19 13:05:49

+0

我更新了我的答案来完成此操作。请看看,看看是否适合你 – Van 2014-12-19 13:12:04