2010-06-08 244 views
2

我在這裏發現了很多關於SO和文章的問題,但都沒有真正解決我的問題。實體框架 - 更新沒有Id的實體

我的模型看起來像這樣(我條紋所有非必要屬性): alt text http://i47.tinypic.com/244p6qh.jpg

每天左右的「PLAY」被更新(通過包含信息的XML文件)。

internal Play ParsePlayInfo(XDocument doc) 
{ 
    Play play = (from p in doc.Descendants("Play") 
    select new Play 
    { 
     Theatre = new Theatre() 
     { 
      //Properties 
     }, 
     //Properties 
     LastUpdate = DateTime.Now 
    }).SingleOrDefault(); 

    var actors = (from a in doc.XPathSelectElement(".//Play//Actors").Nodes() 
    select new Lecturer() 
    { 
     //Properties 
    }); 

    var parts = (from p in doc.XPathSelectElement(".//Play//Parts").Nodes() 
    select new Part() 
    { 
     //Properties 
    }).ToList(); 

    foreach (var item in parts) 
    { 
     play.Parts.Add(item); 
    } 

    var reviews = (from r in doc.XPathSelectElement(".//Play//Reviews").Nodes() 
    select new Review 
    { 
     //Properties 
    }).ToList(); 

    for (int i = 0; i < reviews.Count(); i++) 
    { 
     PlayReviews pR = new PlayReviews() 
     { 
      Review = reviews[i], 
      Play = play, 
      //Properties 
     }; 
     play.PlayReviews.Add(pR); 
    } 
    return play; 
} 

如果我通過Add()添加這個「play」,每個Play對象的子對象都將被插入 - 無論是否已經存在。由於我需要更新現有的條目,所以我必須對此做些事情。我想這裏的問題是我在XML中沒有任何標識。

至於我可以告訴我有以下幾種選擇:

  1. 添加/更新的子實體在我 PlayRepositories添加法
  2. 重組和改寫 ParsePlayInfo(),以便讓所有的 子實體先添加或更新 他們和然後創建一個新的Play。 我這裏唯一的問題是, 我想ParsePlayInfo()是 持久性無知,我可以
  3. 創建多個 解析方法解決此 (如ParseActors()) ,並指定他們在玩我 控制器(我使用ASP.net MVC) 一切後,解析並加入

目前我實現選擇1 - 但感覺不對。

我想要做的是更新已經在數據庫中的實體,並插入新的實體。 在附加/添加遊戲之前,我必須調用SaveChanges()嗎?必須有一個(相對)簡單的解決方案。 我會很感激,如果有人能指導我在這一個正確的方向。

回答

1

好吧,既然沒有答案,我會自己寫一個。

對於那些想知道的人,我得到它的工作 - 代碼看起來很醜,我猜性能更糟糕。但由於不會有很多用戶,而且這種方法只能在晚上每天調用一次,無論如何,我現在對它很好。

我做了什麼?

好吧,我去與選項2和3

private Play UpdatePlay() 
{ 
    using (RepositoryContext context = new RepositoryContext()) 
    { 
     HttpRequest http = new HttpRequest(); 
     PlayRepository rep = new PlayRepository(context); 

     ActorRepository actRep = new ActorRepository(context); 
    ReviewsRepository revRep = new ReviewsRepository(context); 
     TheatreRepository insRep = new TheatreRepository(context); 
     PartRepository partRep = new PartRepository(context); 

     Parser p = new Parser(); 

     XDocument doc = http.GetPlayInfo(); 

     Theatre theatre = p.ParseTheatreInfo(doc); 
     List<Actor> actors = p.ParseActorInfo(doc); 
     List<PlayReviews> playReviews = p.ParseReviewsInfo(doc); 

     for (int i = 0; i < actors.Count; i++) 
     { 
      actors[i] = actRep.AddOrUpdate(actors[i]); 
     } 
     for (int i = 0; i < playReviews.Count; i++) 
     { 
      playReviews[i].Reviews = revRep.AddOrUpdate(playReviews[i].Reviews); 
     } 

     theatre = insRep.AddOrUpdate(theatre); 

     Play play = p.ParsePlayInfo(doc); 

     List<Part> parts = GetParts(play); 

     for (int i = 0; i < parts.Count; i++) 
     { 
      List<Actor> lec = (List<Actor>)parts[i].Actors; 
      for (int j = 0; j < lec.Count; j++) 
      { 
       lec[j] = actRep.AddOrUpdate(lec[j]); 
      } 

     } 

     play = rep.AddOrUpdate(play); 
     context.LoadProperty(play, o => o.Theatre); 
     context.LoadProperty(play, o => o.Actors); 
     context.LoadProperty(play, o => o.PlayReviewss); 
     context.LoadProperty(play, o => o.Parts); 

     rep.Save(); 

     if (play.Theatre != theatre) 
      play.Theatre = theatre; 

     play = rep.AddParts(parts, play); 

     play = rep.AddActor(actors, play); 

     for (int i = 0; i < playReviews.Count; i++) 
     { 
      playReviews[i].Play = play; 
      playReviews[i] = revRep.AddPlayInformation(playReviews[i]); 
     } 

     rep.Save(); 
     return play; 
    } 
} 

(以及在一個側面說明,我才意識到,我以前忘記而我的這部分代碼...)

正如你所看到的,保存()被調用兩次 - 它得到當你考慮什麼更糟糕的AddOrUpdate()事情:

public Actor AddOrUpdate(Actor entity) 
{ 
    Actor cur = context.Actors.Where(l => l.Name == entity.Name && l.Last_Name == entity.Last_Name).FirstOrDefault(); 
    if (cur == null) 
    { 
     context.Actors.AddObject(entity); 
     return entity; 
    } 
    else 
    { 
     if (!entity.Mail.IsNullOrEmptyOrWhitespace() && cur.Mail != entity.Mail) 
      cur.Mail = entity.Mail; 
    //there are more of these... 

     return cur; 
    } 
} 

我不認爲這是「正確」的方式做到這一點。 這感覺,看起來是錯的。也許EF是太怪,拿

FirstEntityType first = new FirstEntityType(); 
first.Id = 2; 
List<SecondType> list = CreateList(); //Let's say this returns a List with 10 elements 
context.FirstEntityType.AddObject(first); 

for (int i = 0; i < list.Count; i++) 
{ 
    list[i].First = first; 
} 

//just for arguments sake a second for 
for (int i = 0; i < list.Count; i++) 
{ 
    context.SecondType.AddObject(list); 
} 

context.SaveChanges(); 

我沒有測試過的代碼,這個特殊的一塊,但是從我所經歷的是,我將有10項新的最終的SecondType,如果我沒看錯的11爲FirstEntityType。

爲什麼?爲什麼EF中沒有一個機制說「嘿,等一下 - 那些都是一樣的!」

我是否錯誤地認爲EF應該像我直接使用db一樣行事?在我的例子中,我添加了「第一」,所以我可以假設每當我使用「第一」它被引用。 (我真的希望我的例子能像所描述的那樣工作 - 沒有時間也沒有想要測試它)

+0

不,你不會得到11個FirstEntityType的條目,只有一個在你的數據庫中。只要你在一個ObjectContext內,當你添加一個對象到上下文時,身份就會被保留。但是,當您再次執行此代碼(在新的上下文中)時,您確實會得到第二個FirstEntityType(或者當FirstEntityType.id是非自動增量主鍵時,會發生dababase異常)。所以:實體框架實際上是這樣說的:「這些都是一樣的!」,但不是感謝相同的id字段,而是因爲AddObject創建了一個(臨時)EntityKey,它在一個ObjectContext中唯一標識該對象。 – Slauma 2010-06-16 00:48:23

+0

我希望我仍然有這樣的代碼,因爲我正在做這樣的事情,並以許多條目結束。而且因爲一切都很好地包裝在使用(上下文){}我很確定我使用了相同的上下文。 也許這是不同的,導致這種行爲或我搞砸了某處。過了一段時間,我非常沮喪,希望完成這項工作。 也許我會做一些測試,如果我有時間。 很高興看到有人讀這一切:) – 2010-06-16 01:08:18