2009-11-11 18 views
8

Öğrenme etkinliği olarak bir blog motoru yazıyorum. Orada bir sürü blog motoru var biliyorum, ama benimle ...Nasıl davranılır NHibernate.NonUniqueObjectException

Bir mülke sahip bir BlogPost varlığım var Etiketler, bu etiketle ilişkili bir IList etiketidir. BlogPost.SetTags (string) yöntemi dizeyi böler, belirtilen etiket adında yeni Tag nesneleri oluşturur ve bunları listeye ekler. BlogPost.AddTag (string tagName) için de aynı.

Gerçekleştirmek istediğim, "foo" adında bir etiket varlığının zaten var olduğu ve veritabanında kalıcı olduğu BlogPost.AddTag ("foo") adını verdiğimde, nHibernate yalnızca bunu fark ediyor ve gönderiyi gönderiyor mevcut etiketle.

BlogRepository.Save() yönteminde, Etiketler listesindeki her etiketin zaten mevcut olup olmadığını kontrol ediyorum. Değilse, bir TagRepository.Save (tag) çağrısı ile kaydedin;

Sorun, aşağıdaki örnek kodda, bir hata alıyorum "NHibernate.NonUniqueObjectException: aynı tanımlayıcı değeri olan farklı bir nesne zaten oturum ile ilişkili: etiketi 1: CMS.Core. Model.Tag "varolan bir etiketi kullanarak bir BlogPost nesnesini sürdürmeye çalıştığımda. Sadece yeni etiketler kullanan bir BlogPost nesnesine devam ettiğimde, bunlar oluşturulur ve her şey yolunda.

Not Ayrıca, TagName bp_Tags tablosu için veritabanındaki birincil anahtar olarak kullanıyorum. Tablo yalnızca benzersiz Etiket adlarını depoladığında bir tamsayı veya GUID PK kullanmak gereksiz görünüyordu.

Benim nHibernate yapılandırma gibi görünüyor:

<class name="CMS.Core.Model.Tag,CMS.Core" table="bp_Tags"> 
    <id column="TagName" name="TagName" type="String" unsaved-value=""> 
     <generator class="assigned" /> 
    </id> 
    </class> 

    <class name="CMS.Core.Model.BlogPost,CMS.Core" table="bp_Content"> 
    <id name="Id" column="Id" type="Int32" unsaved-value="0"> 
     <generator class="native"></generator> 
    </id> 
    <property name="SubmittedBy" column="SubmittedBy" type="string" length="256" not-null="true" /> 
    <property name="SubmittedDate" column="SubmittedDate" type="datetime" not-null="true" /> 
    <property name="PublishDate" column="PublishDate" type="datetime" not-null="true" /> 
    ...  
    <bag name="_tagsList" table="bp_Tags_Mappings" lazy="false" cascade="all"> 
     <key column="Target_Id" /> 
     <many-to-many class="CMS.Core.Model.Tag,CMS.Core" column="TagName" lazy="false" /> 
    </bag> 

NHibernate.NonUniqueObjectException: etiketi 1, varlığın: Aynı tanımlayıcı değerle farklı nesne zaten oturum ile ilişkili bulunmuştur Bariliant.CMS.Core.Model. Etiket

BlogPost post, post2; 

    using (UnitOfWork.Start()) 
    { 
     post = BlogPostFactory.CreateBlogPost("test post", "test body"); 
     post.Publish(); 
     BlogRepository.Save(post); 
     UnitOfWork.Current.Flush(); 

     post.SetTags("tag 1, tag 2"); 
     BlogRepository.Save(post); 
     UnitOfWork.Current.Flush(); 
    } 

    using (UnitOfWork.Start()) 
    { 
     post2 = BlogPostFactory.CreateBlogPost("test post2", "test body"); 
     post2.Publish(); 
     BlogRepository.Save(post2); 
     UnitOfWork.Current.Flush(); 

     post2.AddTag("tag 1"); 
     BlogRepository.Save(post2); // throws 

... yanlış yaptığını ve nasıl bunu düzeltmek için çalışıyorum ne

herhangi bir düşünce?

+2

Sorunun iç ve varolan etiketlerin listesi için olsun yolu geliyor inanıyoruz:

var tag = session.Get<Tag>("Tag 1"); if (tag != null) { post.AddTag(tag); } else { post.AddTag(new Tag("Tag 1")); } 

Bu blog gönderme size ayrıntılı bir açıklama verecektir Yeni olanı ve mevcut olanı yeni BlogPost nesnesine nasıl atadığınızla karşılaştırın. BlogRepository.Save(); kodunun yayınlanması iyi bir fikir olur. Sorunun farkına varmamız için tüm bunların gerçekleştiği yöntem. – tolism7

cevap

8

TagName kimliği olduğundan, NHibernate kimlik haritasını karşılıyorsunuz. Kimlik haritası zaten aynı kimliğe sahip bir nesnenin farkındadır, bu yüzden size bu istisnayı veriyor.

Bu oturumun o oturumda zaten var olup olmadığını görmek istediğiniz yere denemek isteyebilirsiniz ve eğer öyleyse, o etiketin ikinci yazıyla ilişkilendirilmesi gerekir.

Psuedo-kod örneği: NHibernate - Cross session operations

+0

Teşekkürler. Ben benzer bir şey yapmak bitti. Etiketi eklemeden önce veya arayan varlıkları kontrol yapmak için etiket deposuna bir bağımlılık koymadan önce arayanı kontrol etmekten ziyade, içerik deposu ana sınıfındaki kontrolü yaparım. Etiket zaten mevcutsa, "yeni" olanı kaldırırım ve "mevcut" olanı tekrar ekliyorum. Bir çekicilik gibi çalışır ve bağımlılık hedeflerimi bozmaz. –

4

Bu şekilde ilerlemekte olduğunuz yol bende değil, ama sorunun nasıl çözüleceği. Tamamen aynı olan devlet ile 2 ayrı nesneler yaptık

var object1 = new Tag("hello"); 
var object2 = new Tag("hello"); 

var areSame = (object1 == object2); // false 

ancak eşitlik karşılaştırmak eğer o zaman aynı değildir bu yüzden iki farklı nesnelerdir: Normalde nesnesinde aşağıdaki programlama odaklı 2 nesneler eşit DEĞİLDİR . Açıkçası, NHibernate söz konusu olduğunda, bu nesneler aslında aynı varlıktır.

Bunu, Nesne Sınıfı'nın 2 yöntemini geçersiz kılarak NHibernate için çözüyoruz. GetHashCode() ve Eşittir()

GetHashCode() temel olarak bir nesnenin durumuna bağlı olarak benzersiz bir sağlama kodu döndürür. Eşittir'i() eşitlik için iki nesne böyle

karşılaştırılmaktadır:

public override int GetHashCode() 
{ 
    return (this.GetType() + "|" + _tagName).GetHashCode(); 
} 

public override bool Equals(object obj) 
{ 
    return this.GetHashCode() == obj.GetHashCode(); 
} 

Temelde GetHashCode nesne türü ve App.Domain.Tag|nameoftag yani bir dizge olarak etiketin adı birleştirir ve bu dizi için bir karma oluşturur

Eşittir() daha sonra ilk nesnenin GetHashCode() sonucunu, eşitliğin sınanması için ikinci nesnenin GetHashCode() sonucuyla karşılaştırır. Bunu yukarıda tanımladığımız iki nesne ile yaparsanız, iki karma kod aynı olacaktır ve bu nedenle Eşittir() için karşılaştırma doğru olacaktır. NHibernate, kendi iç işlerinde eşitlik için iki nesneyi test ettiğinde, bunların aynı olduğunu ve sorununuzu çözmesi gerektiğini belirleyecektir.

+0

Teşekkürler. Bunları geçersiz kıldım, ancak uygulamalarınızı daha çok beğeniyorum ve bunları benimsedim. –

+0

Bu arada, bu senaryoyu nasıl ele alacağınıza ilişkin girdinizi farklı bir şekilde duymak isterim. –

+3

@Joe: 'GetHashCode' farklı örnekler için benzersiz karma değerler döndürmediğinden,' Equals'ın bu şekilde uygulanmasının önerilmez. Bu şekilde, "Eşittir", ** aslında ** eşit olmayan nesneler için "doğru" döndürebilir. Bu durum istisna sorununuzu çözecektir, ancak örneğin bir "Hashtable" den döndürülen yanlış bir örneği kolayca alabilirsiniz. – Groo