NHibernate - Ters İlişkiler
Bu bölümde, Ters İlişkiler olan başka bir özelliği ele alacağız. Bu, doğruya ters şekilde eşit olan koleksiyonlarda göreceğiniz eğlenceli bir seçenektir ve aynı zamanda birçok geliştiricinin kafasını karıştırır. Öyleyse bu seçenek hakkında konuşalım. Bunu anlamak için gerçekten ilişkisel modeli düşünmeniz gerekiyor. Diyelim ki, tek bir yabancı anahtar kullanan çift yönlü bir ilişkiniz var.
İlişkisel bir bakış açısından, bir yabancı anahtarınız var ve bu hem müşterinin siparişini hem de müşteriye verilen siparişleri temsil ediyor.
OO modelinden, bu referansları kullanan tek yönlü ilişkilere sahipsiniz.
Veritabanında iki tek yönlü ilişkinin aynı çift yönlü ilişkiyi temsil ettiğini söyleyen hiçbir şey yoktur.
Buradaki sorun, NHibernate'in bunu bilmek için yeterli bilgiye sahip olmamasıdır. customer.orders ve order.customer veritabanında aynı ilişkiyi temsil eder.
Sağlamak zorundayız inverse equals true bir ipucu olarak, tek yönlü ilişkilerin aynı verileri kullanmasıdır.
Kendilerine 2 referansı olan bu ilişkileri kaydetmeye çalışırsak, NHibernate bu referansı iki kez güncellemeye çalışacaktır.
Aslında veritabanına fazladan bir gidiş dönüş yapacak ve ayrıca bu yabancı anahtar için 2 güncellemeye sahip olacak.
Ters eşittir doğru, NHibernate'e ilişkinin hangi tarafının yok sayılacağını söyler.
Bunu toplama tarafına uyguladığınızda ve NHibernate yabancı anahtarı her zaman diğer taraftan, alt nesne tarafından güncelleyecektir.
O zaman bu yabancı anahtarda yalnızca bir güncellememiz var ve bu veriler için ek güncellememiz yok.
Bu, yabancı anahtarda bu yinelenen güncellemeleri önlememize olanak tanır ve ayrıca yabancı anahtar ihlallerini önlememize yardımcı olur.
Bir göz atalım customer.cs göreceğiniz dosya AddOrderyöntem ve buradaki fikir, siparişten müşteriye geri dönen bu geri göstergeye sahip olduğumuz ve ayarlanması gerektiğidir. Yani bir müşteriye bir sipariş eklendiğinde, o müşterinin arka işaretçisi ayarlanır, aksi takdirde boş olacaktır, bu yüzden nesne grafiğinde bunu birbirine doğru şekilde bağlı tutmak için buna ihtiyacımız var.
using System;
using System.Text;
using Iesi.Collections.Generic;
namespace NHibernateDemo {
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow; Orders = new HashedSet<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual ISet<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating);
result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
public class Location {
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
public enum CustomerCreditRating {
Excellent,
VeryVeryGood,
VeryGood,
Good,
Neutral,
Poor,
Terrible
}
}
İşte Program.cs dosya uygulaması.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var query = from customer in session.Query<Customer>() where
customer.Id == id select customer;
var reloaded = query.Fetch(x => x.Orders).ToList().First();
Console.WriteLine("Reloaded:"); Console.WriteLine(reloaded);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points = 100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order { Ordered = DateTime.Now };
customer.AddOrder(order1); var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2);
return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Bunu veritabanına kaydedecek ve sonra yeniden yükleyecektir. Şimdi uygulamanızı çalıştıralım ve NHibernate Profiler'ı açalım ve gerçekte nasıl kaydettiğini görelim.
3 grup ifademiz olduğunu fark edeceksiniz. İlki müşteriyi ekleyecektir ve bu müşterinin kimliği vurgulanan Kılavuzdur. İkinci ifade, siparişler tablosuna eklenir.
Orada aynı Müşteri Kimliği Kılavuzunun ayarlandığını fark edeceksiniz, bu nedenle yabancı anahtarı ayarlayın. Son ifade, yabancı anahtarı aynı müşteri kimliğine bir kez daha güncelleyecek güncellemedir.
Şimdi sorun şu ki, müşterinin siparişleri var ve siparişlerin müşterisi var, NHibernate'e bunun aslında aynı ilişki olduğunu söylemememizin bir yolu yok. Bunu yapma şeklimiz ters eşittir doğrudur.
Hadi gidelim bizim customer.hbm.xml eşleme dosyası ve aşağıdaki kodda gösterildiği gibi tersi true olarak ayarlayın.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"
inverse = "true">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Emirleri kaydederken o yabancı anahtarı sipariş tarafından ayarlayacaktır. Şimdi bu uygulamayı tekrar çalıştıralım ve NHibernate profil oluşturucusunu açalım.
Bunların nasıl eklendiğine bakarsak, eki müşteriye ve siparişlere eki alırız, ancak yabancı anahtarın o yinelenen güncellemesine sahip değiliz çünkü siparişler kaydedilirken güncelleniyor.
Şimdi, eğer sadece tek yönlü bir ilişkiniz varsa ve bu ilişkiyi sürdüren küme ise, o zaman ters eşittir doğru çevirirseniz, yabancı anahtarın asla ayarlanmayacağını ve bu öğelerin asla kendilerine sahip olmayacağını not etmelisiniz. veritabanında ayarlanan yabancı anahtarlar.
Bire bir ilişkiye bakarsanız, Order.hbm.xml dosya ve tersini ararsanız, aslında ters niteliği yoktur.
Her zaman alt öğeden ayarlanır, ancak çoktan çoğa bir koleksiyonunuz varsa, her iki taraftan da ayarlayabilirsiniz.