2

코드 첫 번째 유창한 표기법을 사용하여 EF6에 매핑 한 POCO의 개체 그래프를 저장하려고합니다.Entity Framework 코드를 사용하여 분리 된 개체 그래프 저장 우선 기본 키 위반 발생

그러나 개체 그래프를 저장하면 기본 키 위반 예외가 발생합니다.

객체 그래프가 매우 간단하다 :

Issue 하나는 여러 WorkItems 포함될 수 각 Author (User 등).

객체가 나는 같은 저자을 참조 두 개의 작업 항목에 문제를 저장하려고하면, 내가 문제가 삽입 기대

(웹 API를 사용하여) 외부 채워의 작업 항목이 삽입되는 한 명의 작성자가 삽입되고 다른 하나는 참조되거나 업데이트되어야합니다.

그러나 문제가 삽입되면 작업 항목이 삽입되고 동일한 사용자에 대한 참조가 모두 삽입되어 기본 키 위반이 발생합니다.

간체 문제 개체 :

public class Issue 
{ 
    public Issue() 
    { 
     WorkItems = new List<WorkItem>(); 
    } 

    public string Id { get; set; } 

    private List<WorkItem> _workItems; 
    public List<WorkItem> WorkItems 
    { 
     get { return _workItems ?? new List<WorkItem>(); } 
     set { _workItems = value; } 
    } 
} 

간체 WorkItem에서 :

public class WorkItem 
{ 
    public string Id { get; set; } 

    public string AuthorLogin 
    { 
     get; set; 
    } 

    private WorkItemAuthor _author; 
    public WorkItemAuthor Author 
    { 
     get { return _author; } 
     set { _author = value; 
      if (value != null) 
      { 
       AuthorLogin = value.Login; 
      } 
      else 
      { 
       AuthorLogin = string.Empty; 
      } 
     } 
    } 
} 

단순화 된 사용자 개체 :

public class User 
{ 
    public string Login { get; set; } 
    public string FullName { get; set; } 
} 

그들의 코드 - 첫번째 구성 :

internal IssueConfiguration() 
    { 
     HasKey(x => x.Id); 
     HasMany(x => x.WorkItems); 
    } 
    internal WorkItemConfiguration() 
    { 
     HasKey(x => x.Id); 

     HasRequired(p => p.Author) 
      .WithMany(b => b.WorkItems) 
      .HasForeignKey(x=>x.AuthorLogin); 
    } 
    internal UsersConfiguration() 
    { 
     HasKey(x => x.Login); 
    } 

모두 매우 간단합니다. 데이터베이스를 만들면 테이블이 멋지게 멋지게 보입니다. FK를 사용하여 열이 예상됩니다.

이제 문제를 저장할 때 객체 그래프를 삽입하면 기존의 참조가 좋을 것입니다. 객체는 자동으로 인식되고 선택적으로 삽입되거나 참조 만됩니다.

나는 그에 따라 문제를 추가하려고 :

using (var db = new Cache.Context()) 
{ 
    if (db.Issues.Any(e => e.Id == issue.Id)) 
    { 
     db.Issues.Attach(issue); 
     db.Entry(issue).State = EntityState.Modified; 
    } 
    else 
    { 
     db.Issues.Add(issue); 
    } 
    db.SaveChanges(); 
} 

내가 수동으로 추가하거나 너무 그래프에서 다른 객체를 연결하는 객체 그래프를 걸어이 문제에 대한 해결책인가? 나는이 참조가 인식 될 적절한 외래 키 값을 정의함으로써 기대할 것이다.

답변

1

나는 이와 비슷한 일을 마침내 끝내었고, 힘들었고 나는 여전히 더 나은 길을 찾고 싶습니다. 엔티티가 이미 연결되어 있거나 데이터베이스에 존재하는지 확인하면 모델을 너무 많이 오염시킬 수 있습니다. (IEquatable<T>을 구현하는 것이 좋습니다. 그러나 내 POCO에 IEntityWithKey을 구현하면 POCO가 너무 많이 오염됩니다. .

internal static void Save(this List<Issue> issues) 
{ 
    using (var db = new Context()) 
    { 
     foreach (var issue in issues.ToList()) 
     { 

      foreach (var workItem in issue.WorkItems.ToList()) 
      { 
       if (workItem.Author != null) 
       { 
        var existing = db.Users.SingleOrDefault(e => e.Login == workItem.Author.Login); 
        if (existing == null) 
        { 
         db.Users.Add(workItem.Author); 
        } 
        else 
        { 
         //Update existing entities' properties 
         existing.Url = workItem.Author.Url; 

         //Replace reference 
         workItem.Author = existing; 
        } 
        db.SaveChanges(); 
       } 

       var existingWorkItem = db.WorkItems.SingleOrDefault(e => e.Id == workItem.Id); 
       if (existingWorkItem == null) 
       { 
        db.WorkItems.Add(workItem); 
       } 
       else 
       { 
        //Update existing entities' properties 
        existingWorkItem.Duration = workItem.Duration; 

        //Replace reference 
        issue.WorkItems.Remove(workItem); 
        issue.WorkItems.Add(existingWorkItem); 
       } 

       db.SaveChanges(); 
      } 


      var existingIssue = db.Issues.SingleOrDefault(x => x.Id == issue.Id); 
      if (existingIssue == null) 
      { 
       db.Issues.Add(issue); 
      } 
      else 
      { 
       //Update existing entities' properties 
       existingIssue.SpentTime = issue.SpentTime; 
      } 

      db.SaveChanges(); 
     } 
    } 
} 
0

이 문제 개체의 작은 버그가 있습니다) 맥락에서 실체를 추적 충분하기

을 "_workItems를 반환 ?? 새 목록();"_workItems 경우 얻을 수있는 모든에 대한 새로운 WorkItem에서를 반환 할 수 이제까지는 null이되었습니다.다음은 고정 버전입니다.

public class Issue { 
    public Issue() { 
     WorkItems = new List<WorkItem>(); 
    } 

    public String Id { 
     get; set; 
    } 

    public List<WorkItem> WorkItems { get; private set; } 
} 
+0

개인 설정자는 내가 실수하지 않는다면 EF에서 설정하는 것을 금지합니다. 또 다른 해결 방법은 다음과 같습니다. 'get {return _workItems ?? (_workItems = new List ()); "}' –

+0

Aha, 동의합니다. 다음 생성자에서 새 항목을 제거 할 수도 있습니다. :) – AIBrain

관련 문제