NHibernate - Hubungan Invers

Dalam bab ini, kita akan membahas fitur lain yaitu Hubungan Invers. Ini adalah opsi lucu yang akan Anda lihat pada koleksi yang berbanding terbalik dengan true dan juga membingungkan banyak pengembang. Jadi mari kita bicara tentang opsi ini. Untuk memahami ini, Anda benar-benar harus memikirkan model relasional. Misalkan Anda memiliki asosiasi dua arah menggunakan kunci asing tunggal.

  • Dari sudut pandang relasional, Anda memiliki satu kunci asing, dan itu mewakili pelanggan untuk memesan dan memesan ke pelanggan.

  • Dari model OO, Anda memiliki asosiasi searah menggunakan referensi ini.

  • Tidak ada yang mengatakan bahwa dua asosiasi searah mewakili asosiasi dua arah yang sama dalam database.

  • Masalahnya di sini adalah NHibernate tidak memiliki cukup informasi untuk mengetahuinya customer.orders dan order.customer merepresentasikan hubungan yang sama dalam database.

  • Kami perlu menyediakan inverse equals true sebagai petunjuk, ini karena asosiasi searah menggunakan data yang sama.

  • Jika kami mencoba untuk menyimpan hubungan yang memiliki 2 referensi ke mereka, NHibernate akan mencoba memperbarui referensi itu dua kali.

  • Ini benar-benar akan melakukan perjalanan bolak-balik ekstra ke database, dan juga akan memiliki 2 pembaruan untuk kunci asing tersebut.

  • Pembalikan sama dengan benar memberi tahu NHibernate sisi mana dari hubungan yang harus diabaikan.

  • Ketika Anda menerapkannya ke sisi koleksi dan NHibernate akan selalu memperbarui kunci asing dari sisi lain, dari sisi objek turunan.

  • Kemudian kami hanya memiliki satu pembaruan untuk kunci asing itu dan kami tidak memiliki pembaruan tambahan untuk data itu.

  • Hal ini memungkinkan kami untuk mencegah duplikasi pembaruan kunci asing ini dan juga membantu kami mencegah pelanggaran kunci asing.

Mari kita lihat customer.cs file di mana Anda akan melihat AddOrdermetode dan idenya di sini adalah bahwa kita sekarang memiliki penunjuk kembali ini dari pesanan kembali ke pelanggan dan itu perlu disetel. Jadi, ketika pesanan ditambahkan ke pelanggan, penunjuk belakang pelanggan itu disetel, jika tidak, itu akan menjadi nol, jadi kami membutuhkan ini untuk tetap terhubung dengan benar bersama dalam grafik objek.

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 
   } 
}

Ini dia Program.cs implementasi file.

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; 
      } 
   } 
}

Ini akan menyimpannya ke database dan kemudian memuatnya kembali. Sekarang mari kita jalankan aplikasi Anda dan buka NHibernate Profiler dan lihat bagaimana sebenarnya itu menyimpannya.

Anda akan melihat bahwa kami memiliki 3 kelompok pernyataan. Yang pertama akan memasukkan pelanggan, dan ID pelanggan itu adalah Panduan, yang disorot. Pernyataan kedua dimasukkan ke dalam tabel pesanan.

Anda akan melihat Panduan Id Pelanggan yang sama diatur di sana, jadi atur kunci asing itu. Pernyataan terakhir adalah pembaruan, yang akan memperbarui kunci asing ke id pelanggan yang sama sekali lagi.

Sekarang masalahnya adalah pelanggan memiliki pesanan, dan pesanan memiliki pelanggan, tidak mungkin kami belum memberi tahu NHibernate bahwa itu sebenarnya hubungan yang sama. Cara kita melakukannya adalah dengan invers sama dengan true.

Jadi mari kita pergi ke customer.hbm.xml file pemetaan dan atur inversi sama dengan true seperti yang ditunjukkan pada kode berikut.

<?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>

Saat menyimpan pesanan, itu akan mengatur kunci asing itu dari sisi pesanan. Sekarang mari kita jalankan aplikasi ini lagi dan buka profiler NHibernate.

Jika kita melihat bagaimana itu dimasukkan, kita mendapatkan sisipan di pelanggan, dan sisipkan ke dalam pesanan, tapi kita tidak memiliki pembaruan duplikat dari kunci asing karena itu diperbarui ketika pesanan disimpan.

  • Sekarang, Anda harus mencatat bahwa jika Anda hanya memiliki asosiasi searah dan himpunanlah yang mempertahankan hubungan ini, maka jika Anda mengubah invers sama dengan true, kunci asing itu tidak akan pernah disetel, dan item tersebut tidak akan pernah memiliki kunci asing diatur dalam database.

  • Jika Anda melihat hubungan banyak-ke-satu di file Order.hbm.xml file dan Anda mencari invers, itu sebenarnya tidak memiliki atribut invers.

  • Ini selalu disetel dari item anak, tetapi jika Anda memiliki koleksi banyak ke banyak, Anda dapat menyetelnya dari kedua sisi.