开发手册 欢迎您!
软件开发者资料库

NHibernate - 反向关系

NHibernate反向关系 - 从概述,架构,Orm,环境设置,入门,基本Orm,基本Crud操作,Profiler,添加Intelliesnse到映射文件,数据类型映射,配置,覆盖配置,批量大小,缓存,映射,学习NHibernate组件,关系,集合映射,级联,延迟加载,反向关系,加载/获取,Linq,Hibernate查询语言,条件查询,QueryOver查询,本机Sql,流利Hibernate。

在本章中,我们将介绍另一个反向关系特征.这是一个有趣的选项,你会在集合上看到它与true相反,它也会让许多开发人员感到困惑.那么让我们谈谈这个选项.要理解这一点,您必须考虑关系模型.假设您使用单个外键进行双向关联.

  • 从关系角度来看,您有一个外键,它代表客户订购和订单给客户.

  • 从OO模型中,您可以使用这些参考进行单向关联.

  • 没有任何内容表明两个单向关联在数据库中表示相同的双向关联.

  • 问题这里是NHibernate没有足够的信息知道 customer.orders order.customer 代表数据库中的相同关系.

  • 我们需要提供 inverse equals true 作为提示,这是因为单向关联使用相同的数据.

  • 如果我们尝试保存这些有2个引用的关系,NHibernate会尝试两次更新该引用.

  • 反向等于true告诉NHibernate忽略关系的哪一方.

  • 当你将它应用到收集方时,NHibernate将始终从另一方更新外键,子对象端.

  • 然后我们只对该外键进行一次更新,我们没有对该数据的其他更新.

  • 这使我们可以防止对外键的这些重复更新,这也有助于我们防止外键违规.

让我们看一下 customer.cs 文件,您将在其中看到 AddOrder 方法,这里的想法是我们现在拥有的这个后退指针从订单返回到客户,需要进行设置.因此,当一个订单被添加到客户时,该客户的后退指针被设置,否则,它将为空,因此我们需要这个以在对象图中将它们正确连接在一起.

using System; using System.Text; using Iesi.Collections.Generic;namespace NHibernateDemo {    public class Customer {             public Customer() {         MemberSince = DateTime.UtcNow; Orders = new HashedSet();      }             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 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    }}

这是 Program.cs 文件实现.

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() 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  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();             x.Dialect();             x.IsolationLevel = IsolationLevel.RepeatableRead;             x.Timeout = 10;             x.BatchSize = 10;          });                   cfg.SessionFactory().GenerateStatistics();         cfg.AddAssembly(Assembly.GetExecutingAssembly());          return cfg;       }    } }

它会将其保存到数据库然后重新加载.现在让我们运行你的应用程序并打开NHibernate Profiler,看看它是如何实际保存它的.

反向NHibernate Profiler

您会注意到我们有3组语句.第一个将插入客户,该客户的ID是Guid,突出显示.第二个语句是插入到订单表中.

Customer Id Guid

您会注意到在那里设置了相同的Customer Id Guid,因此设置了该外键.最后一个语句是更新,它将再次将外键更新为相同的客户ID.

Customer Hbm

现在的问题是客户有订单,订单有客户,我们没有办法告诉NHibernate它实际上是相同的关系.我们这样做的方法是反等于真.

所以让我们转到我们的 customer.hbm.xml 映射文件并设置反转等于true,如图所示在以下代码中.

                                                                                                                                                                                               

保存订单时,它会从订单侧设置该外键.现在让我们再次运行这个应用程序并打开NHibernate探查器.

外键

如果我们看看它们是如何插入的,我们在客户中获得插入,并插入订单,但我们没有外键的重复更新,因为它在保存订单时正在更新./p>

  • 现在,您应该注意,如果您只有单向关联,并且它是维持此关系的集合,那么如果反转等于true,则永远不会设置外键,并且这些项永远不会在数据库中设置外键.

  • 如果您查看 Order.hbm.xml 文件中的多对一关系,并且您查找了反向关系,则它实际上没有反向属性.

  • 它总是从子项设置,但如果你有一个多对多的集合,你可以从任何一方设置它.