2014-12-19 167 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