2010-11-19 21 views
1

Bir NHibernate projesi üzerinde çalışıyorum ve geçici varlıkların güncellenmesiyle ilgili bir sorum var. aşağıdaki gibiNHibernate - belirli özellikleri 'kirli' olarak işaretleme

Temelde iş akışı:

  1. bir DTO (projeksiyon) oluşturun ve müşteriye teli yolla. Bu, varlıktan küçük bir özellik kümesine sahiptir.
  2. Müşteri değiştirilen DTO'yu geri gönderir
  3. DTO özelliklerini uygun enititeye eşleştirin, böylece UPDATE ifadesi NH tarafından oluşturulabilir ve yürütülebilir. Sorunu sahip olduğu
  4. kaydet varlık

Nokta 4'tür. Şu anda bu güncellemeyi session.Merge() yöntemini kullanarak elde edebilirim, ancak önce güncellemeden önce varlığı db'den (2LC almayın) yüklemelisiniz. Yani, hem bir seçim hem de güncelleme bildirisi tetiklendi.

Yapmak istediğim şey, varlığın geçici bir örneğini oluşturmak, yeni değerleri DTO'dan eşlemek, ardından NH'nin yalnızca değiştirdiğim özellikleri kullanarak bir SQL deyimi oluşturmasıdır. Varlık kimliğinin ve SET cümlesi için gereken değerlerin zaten olması nedeniyle ek seçimin gereksiz olması gerekir. Bu NH'de mümkün mü?

Şu anda session.Update() işlevini kullanarak, tüm özellikler güncelleştirme ifadesine dahil edilecek ve DTO'nun parçası olmayan başlatılmamış özellikler nedeniyle bir istisna kaldırılacaktır.

Esas olarak, hangi varlık özelliklerinin kirli olduğunu belirtmenin bir yoluna ihtiyacım var, bu nedenle yalnızca bunlar güncellemeye dahil edildi.

== DÜZENLEME == Örneğin

...

public class Person 
{ 
    public virtual int PersonId { get; set; } 
    public virtual string Firstname { get; set; } 
    public virtual string Nickname { get; set; }  
    public virtual string Surname { get; set; } 
    public virtual DateTime BirthDate { get; set; }  
} 

Ve test durumu.

// Create the transient entity 
Person p = new Person() 
p.id = 1; 

using (ISession session = factory.OpenSession()) 
{ 
    session.Update(p); 

    // Update the entity – now attached to session  
    p.Firstname = “Bob”; 

    session.Flush(); 
} 

Ben ‘UPDATE kişiler SET Isim =‘Bob’NEREDE PersonID = 1’ benzer bir SQL deyimi oluşturmak için umuyordum. Bunun yerine, BirthDate'in başlatılmaması nedeniyle bir DateTime aralık aralığı dışında bir durum alıyorum. SQL deyimi için gerekli olmadığından Doğum Tarihi'ne gerek duyulmamalıdır. Belki bu mümkün değil mi? peşin

==/DÜZENLEME ==

sayesinde John

cevap

4

Dinamik güncelleme aradığınız budur. Eşleme dosyanızda (hbm.xml):

Bunun neden olabileceği olası sorunlardan haberdar olun. Birinci Ad veya Takma adın boş olmaması gerektiğini belirten bazı alan adı mantığınız olduğunu varsayalım. (Tamamen bunu yapıyoruz.) İki kişi aynı anda Jon "Jonboy" Jonson'ı günceller. Biri onun FirstName kaldırır. Dinamik güncelleme doğru olduğundan, güncelleme bildirimi sadece Jon'u geçersiz kılar ve kayıt artık "Jonboy" Jonson'dur. Diğer eş zamanlı güncelleme Takma Adını kaldırır. Amaç Jon Jonboy. Ancak sadece takma adın boş olduğu veritabanına gönderilir. Artık Adsız veya Takma adsız bir kaydınız var.Dinamik güncelleme yanlışsa, ikinci güncelleme onu Jon Jonboy'a ayarlamış olur. Belki durumunuzda bu bir sorun değildir, ancak dinamik-update = "true" ayarının sonuçları vardır ve sonuçları düşünmeniz gerekir.

GÜNCELLEME: Kod için teşekkürler. Bu yardımcı oldu. Temel sorun, NHibernate'in yeterli bilgiye sahip olmamasıdır. Session.Update (p) ifadesini kullandığınızda, NHibernate bağlantısız bir varlığı geçerli oturumla ilişkilendirmelidir. Varsayılan olmayan bir PK'ye sahiptir. Yani NHibernate, bunun bir güncellemedir ve bir ek olmadığını bilir. Session.Update (p) ifadesini kullandığınızda, NHibernate tüm varlığı kirli olarak görür ve veritabanına gönderir. (Eğer session.Merge (obj) kullanırsanız, NHibernate nesneyi veritabanından seçer ve objeyi onunla birleştirir.) Bu gerçekten demek istediğin şey değil. Nesnenizi mevcut oturumla ilişkilendirmek, ancak temiz olarak işaretlemek istersiniz. API biraz sezgisel değil. Aşağıdaki gibi session.Lock (obj, LockMode.None) kullanın.

using(var session = sessionFactory.OpenSession()) 
using(var tx = session.BeginTransaction()) { 
    var p = new Person {PersonId = 1}; 
    session.Lock(p, LockMode.None); // <-- This is the secret sauce! 
    p.Firstname = "Bob"; 
    // No need to call session.Update(p) since p is already associated with the session. 
    tx.Commit(); 
} 

(NB dinamik update = "true" benim haritalama belirtilir.) Bu, aşağıdaki SQL sonuçlanır

:

UPDATE Person 
SET Firstname = 'Bob' /* @p0_0 */ 
WHERE PersonId = 1 /* @p1_0 */ 
+0

de bu kullanmanın performans etkileri de vardır , Ben statik güncelleştirmeleri kullanarak (genel) nhibernate sessionfactory inşa edildiğinde güncelleştirme deyimleri hazırladığı nedeniyle daha performanslı olduğuna inanıyorum. – DanP

+0

Merhaba James, Yanıt için teşekkürler. Varlık için ayarlanmış DynamicUpdate (akıcı haritalama) var. Belki bir örnek problemi daha açık bir şekilde gösterecektir. Lütfen yukarıda düzenlenen bölümlere bakınız. – John

+0

API'nın bu durumda sezgisel olmadığını kabul etmeliyim;) 'real-world' uygulamasında session.Lock() kullanarak test ettim ve tam olarak istediğim SQL'i döndürüyor. Bu James'le ilgili yardımlarınız için çok teşekkürler. – John

İlgili konular