2013-03-07 21 views
17

Bu özel hata iletisiyle ilgili bazı soruları/yanıtları okudum, ancak uygun çözümü tam olarak anlamadım.İki nesne arasındaki ilişki, farklı ObjectContext nesnelerine eklendikleri için tanımlanamaz.

EF4 içeriğini oluşturmanız, kullanmanız ve sonra imha etmeniz gerektiğini defalarca okudum. Uygulamam boyunca, burada ve orada farklı bağlam nesneleri kullanarak varlıkları yüklüyorum ve daha sonra varlıkları birlikte ilişkilendirmek istiyorum.

Hataya neden olan basit bir konsol uygulaması oluşturdum. Çok basit model şema ile takip edilir.

Aynı bağlamı paylaşmak için iki farklı varlıkları nasıl alabilirim? Gerçekten yeni bir içerik oluşturmalı mıyım, iki varlığı tekrar yüklemeliyim (zaten sahip olmalarına rağmen), sadece onları ilişkilendirmek ve kaydetmek?

Zaten mevcut, uygun bir soru/cevap özledim, lütfen beni doğru yere yönlendirin.

Simple EF4 Model diagram

internal class Program { 

    private static void Main(string[] args) { 
     DeleteAllEntities(); 
     CreateInitialEntities(); 
     Owner o = LoadOwner(); 
     Child c = LoadChild(); 
     AssociateAndSave(o, c); 
    } 

    private static void AssociateAndSave(Owner o, Child c) { 
     using (var context = new ModelEntities()) { 
      // Exception occurs on the following line. 
      o.Children.Add(c); 
      context.Attach(o); 
      context.SaveChanges(); 
     } 
    } 

    private static Owner LoadOwner() { 
     using (var context = new ModelEntities()) { 
      return ((from o in context.Owners 
        select o).First()); 
     } 
    } 

    private static Child LoadChild() { 
     using (var context = new ModelEntities()) { 
      return ((from c in context.Children 
        select c).First()); 
     } 
    } 

    private static void CreateInitialEntities() { 
     using (var context = new ModelEntities()) { 
      Owner owner = new Owner(); 
      Child child = new Child(); 
      context.Owners.AddObject(owner); 
      context.Children.AddObject(child); 
      context.SaveChanges(); 
     } 
    } 

    private static void DeleteAllEntities() { 
     using (var context = new ModelEntities()) { 
      List<Child> children = (from c in context.Children 
            select c).ToList(); 
      foreach (var c in children) 
       context.Children.DeleteObject(c); 
      List<Owner> owners = (from o in context.Owners 
            select o).ToList(); 
      foreach (var o in owners) 
       context.Owners.DeleteObject(o); 
      context.SaveChanges(); 
     } 
    } 
} 
+1

Hmm .. Sadece 'context.Attach (o); context.Attach (c); 'hatayı önler. Ancak bunu gerçek uygulamamda denediğimde, 'ObjectStateManager'da aynı anahtarın bulunduğu bir nesne var. Nesneler bu örneğe benzer bir şekilde yüklenmiş olsa bile, ObjectStateManager aynı nesneye sahip birden fazla nesneyi izleyemez. ” – Steve

cevap

15

Aynı içerikteki alt öğe ve sahip nesnelerine başvuruda bulunmalısınız. Bunun için bir yaklaşım, kimlikleri almak ve daha sonra AssociateAndSave(int oId, int cId) yöntemine parametreler olarak geçirmektir.

Daha sonra, aynı bağlamda nesnesine yapılan başvuruları nesnelerine aktarırsınız ve eki siz yaparsınız.

private static void Main(string[] args) 
{ 
    DeleteAllEntities(); 
    CreateInitialEntities(); 
    int oId = LoadOwnerId(); 
    int cId = LoadChildId(); 
    AssociateAndSave(oId, cId); 
} 

private static int LoadOwnerId() 
{ 
    using (var context = new ModelEntities()) 
    { 
     return (from o in context.Owners 
       select o).First().Id; 
    } 
} 

private static int LoadChildId() 
{ 
    using (var context = new ModelEntities()) 
    { 
     return (from c in context.Children 
       select c).First().Id; 
    } 
} 

private static void AssociateAndSave(int oId, int cId) 
{ 
    using (var context = new ModelEntities()) 
    { 
     var owner = (from o in context.Owners 
         select o).FirstOrDefault(o => o.ID == oId); 
     var child = (from o in context.Children 
         select o).FirstOrDefault(c => c.ID == cId); 

     owner.Children.Add(child); 
     context.Attach(owner); 
     context.SaveChanges(); 
    } 
} 
+1

Bu, EF 4.0 – Freeman

+2

'da çalışmayacak olmasına rağmen iyi bir çözümdür. Aslında bunu yapmaya başladım, ama daha önce veritabanından yüklediğim varlık için veritabanını sorgulamanın biraz israf olduğunu düşünmüştüm. – Steve

+1

Bu soruya her iki cevabın bir kısmıyla gitmeye karar verdim, ancak maalesef ikisini de cevap olarak işaretleyemem .. :) Bunu arayan herkes de http://stackoverflow.com/a/5695009/425871 adresini görmelidir. . – Steve

3

her bağlam ayrı nesnelerini izler, çünkü başka bir bağlamda bir örneğiyle birlikte, bir bağlamdan nesneleri silemezsiniz.

Bir ideea, yöntemlerin her birini bağlam türünüzün bir parametresini sağlamaktır, böylece işlemleriniz aynı bağlamda yapılır.

EX:

private static void CrudOperationExample(DBContext contextInstane) 
{ 
    //perform crud operations. 
} 

daha güzel yapmak istiyorum ben, ben bunu çok yararlı ORM en olduğu gibi, bağımlılık enjeksiyon aramanızı öneriyoruz.

+1

Bir bağlamı canlı tutardım, böylece bunu yapabilirdim, ama tekrar tekrar okurum. İhtiyacınız olduğunda, içeriği sadece çok kısa bir süre için saklayın. Uygulamamda, içeriğin 5 dakika veya belki bir saat bile açık olabileceği mümkün. Kullanıcının pencereyi ne kadar açık tuttuğuna bağlı. – Steve

+1

Ayrıca - her bir bağlamın varlıklarını ayrı ayrı izlediğini söylüyorsunuz, ancak içerik bertaraf edildi (tüm işlemlerim 'block'larda kullanılıyor). – Steve