NHibernate 备忘-- 级联问题 (转)

在用NHibernate碰到一个级联操作问题,在各位大侠的帮助下总算是给搞清楚了,好了废话不说,看问题。

 Customer对多个Order,典型的一对多关系,代码如下,不多讲。

<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--&gt  1     public   class  Customer
 2      {
 3          ISet < Order >  _orders  =   new  HashedSet < Order > ();
 4 
 5           public   virtual   int  CustomerID {  get set ; }
 6           public   virtual   string  CustomerName {  get set ; }
 7           public   virtual  ISet < Order >  Orders
 8          {
 9               get
10              {
11                   return  _orders;
12              }
13               set
14              {
15                  _orders  =  value;
16              }
17          }
18 
19           ///  
20           ///  添加一个订单
21           ///  
22           ///  
23           ///  
24           public   virtual   int  AddOrder(Order o)
25          {
26              Orders.Add(o);
27              o.Customer  =   this ;
28               return  Orders.Count;
29          }
30 
31           ///  
32           ///  移除一个订单
33           ///  
34           ///  
35           ///  
36           public   virtual   int  RemoveOrder(Order o)
37          {
38              Orders.Remove(o);
39               return  Orders.Count;
40          }
41      }
42 
43       ///  
44       ///  订单
45       ///  
46       public   class  Order
47      {
48           public   virtual   int  OrderID {  get set ; }
49           public   virtual   int  ProductNum {  get set ; }
50           public   virtual  Customer Customer {  get set ; }
51      }

      刚开始的时候,我设置 inverse="false",在保存Customer的时候,NH自动为我保存了Order,感觉很方便,后来删除Customer的时候,引发了一个异常,说是外键不允许为空,很奇怪,我删除数据怎么会让外键为空?后来发现了问题:没看到NH输出delete语句,只看到有两条将外键更新为空的update语句,但是奇怪的是数据却被删掉了,为了搞清楚这个问题,于是有了下文。后来在李永京的建议下,使用NHProfiler监视,发现了NH生成的delete语句,看来是testDriver.Net的问题,漏掉了某些输出的sql语句。

      关于级联删除,nh在级联删除的时候总是先Update,然后在delete,这是因为inverse属性设置的原因,我们着重看看这个属性。

      我们先让inverse默认为false,使用如下代码创建Customer。

 1         [Test] 

 2        public  void CreateCustomer()
 3        {
 4            Customer cus =new Customer();
 5            cus.CustomerName ="test";
 6            cus.Orders.Add(new Order { ProductNum =1 });
 7            cus.Orders.Add(new Order { ProductNum =2 });

 8            NHibernateHelper.EncloseInTransaction(s =>

 9                {
10                    s.Save(cus);
11                });
12        }

 第四行是一个自定义的执行事务的方法,直接粘贴李永京写的。

<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--&gt  1            public   static   void  EncloseInTransaction(Action < ISession >  work)
 2           {
 3               if  (sessionFactory  ==   null )
 4              {
 5                  Configuration cfg  =   new  Configuration();
 6                  cfg  =  cfg.Configure();
 7                  sessionFactory  =  cfg.BuildSessionFactory();
 8              }
 9               using  (var s  =  sessionFactory.OpenSession())
10              {
11                   using  (var tx  =  s.BeginTransaction())
12                  {
13                       try
14                      {
15                          work(s);
16                          tx.Commit();
17                      }
18                       catch
19                      {
20                          tx.Rollback();
21                           throw ;
22                      }
23                  }
24              }
25          }

      注意,这里我们直接使用ISet的Add方法加入订单,我们看看NH生成的语句:

<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --&gt 1  NHibernate:  INSERT   INTO   [ Customer ]  (CustomerName)  VALUES  ( @p0 );  select   SCOPE_IDENTITY (); @p0   =   ' test '
2  NHibernate:  INSERT   INTO   [ Order ]  (ProductNum, CustomerID)  VALUES  ( @p0 @p1 );  select   SCOPE_IDENTITY (); @p0   =   1 @p1   =   NULL
3  NHibernate:  INSERT   INTO   [ Order ]  (ProductNum, CustomerID)  VALUES  ( @p0 @p1 );  select   SCOPE_IDENTITY (); @p0   =   2 @p1   =   NULL
4  NHibernate: Batch commands:
5  command  0 : UPDATE   [ Order ]   SET  CustomerID  =   @p0   WHERE  OrderID  =   @p1 ; @p0   =   6 @p1   =   11
6  command  1 : UPDATE   [ Order ]   SET  CustomerID  =   @p0   WHERE  OrderID  =   @p1 ; @p0   =   6 @p1   =   12

      有什么感觉?先插入为两条外键为空的记录,然后在用update更新外键,很别扭吧,如果你的数据库外键不允许为空,还会引发异常。先别急,接着我们看看删除。用以下代码删除一个客户 : 

1[Test]     

2public void DeleteCustomer()
3{
4    NHibernateHelper.EncloseInTransaction(s =>

5    {
6     Customer cus = s.Load<Customer>(1);
7     s.Delete(cus);
   });
9}

 看看NH生成的代码:

<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --&gt  1  NHibernate:  SELECT  customer0_.CustomerID  as  CustomerID1_0_, customer0_.CustomerName  as  Customer2_1_0_  FROM   [ Customer ]  customer0_  WHERE  customer0_.CustomerID = @p0 ; @p0   =   2
 2  NHibernate:  SELECT  orders0_.CustomerID  as  CustomerID1_, orders0_.OrderID  as  OrderID1_, orders0_.OrderID  as  OrderID0_0_, orders0_.ProductNum  as  ProductNum0_0_, orders0_.CustomerID  as  CustomerID0_0_  FROM   [ Order ]  orders0_  WHERE  orders0_.CustomerID = @p0 ; @p0   =   2
 3  NHibernate:  UPDATE   [ Order ]   SET  CustomerID  =   null   WHERE  CustomerID  =   @p0 ; @p0   =   2
 4  NHibernate: Batch commands:
 5  command  0 : DELETE   FROM   [ Order ]   WHERE  OrderID  =   @p0 ; @p0   =   3
 6  command  1 : DELETE   FROM   [ Order ]   WHERE  OrderID  =   @p0 ; @p0   =   4
 7 
 8  NHibernate: Batch commands:
 9  command  0 : DELETE   FROM   [ Customer ]   WHERE  CustomerID  =   @p0 ; @p0   =   2
10 

      我们注意第三行的那个语句,发现什么了?原来NH先把子对象的外键置空,然后才去删除子对象,最后才去删除父对象 这显然不是我们想要的,在插入的时候,我们希望是三条insert,删除的时候能不能不要那个update,有的时候外键不允许为空还会引发异常!

     当设置inverse="true时,我们应该使用 Customer的AddOrder方法(代码见Customer实体类)来添加订单,如果你还是直接调用Orders属性的话,那么订单对象的Customer属性将会为空,那么插入到数据库中后外键也是空(可以把后面的代码下载下来改一下试试)! 我们修改一下创建客户的代码:

  1         [Test]   

 2        public void CreateCustomer()
 3        {
 4            Customer cus =new Customer();
 5            cus.CustomerName ="test";
 6            cus.AddOrder(new Order { ProductNum =1 });
 7            cus.AddOrder(new Order { ProductNum =2 });

 8            NHibernateHelper.EncloseInTransaction(s =>10                {
 9                    s.Save(cus);
10                });
11        }

   注意第六第七行,运行测试,我们看看输出的sql语句,正式我们想要的形式了。

ExpandedBlockStart.gif 当 inverse="true"时输出的sql语句
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --&gt NHibernate:  INSERT   INTO   [ Customer ]  (CustomerName)  VALUES  ( @p0 );  select   SCOPE_IDENTITY (); @p0   =   ' test '
NHibernate:  INSERT   INTO   [ Order ]  (ProductNum, CustomerID)  VALUES  ( @p0 @p1 );  select   SCOPE_IDENTITY (); @p0   =   1 @p1   =   4
NHibernate:  INSERT   INTO   [ Order ]  (ProductNum, CustomerID)  VALUES  ( @p0 @p1 );  select   SCOPE_IDENTITY (); @p0   =   2 @p1   =   4

我们在看看删除输出的sql语句,是不是没有那个update?

<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--&gt 1  NHibernate: SELECT customer0_.CustomerID as CustomerID1_0_, customer0_.CustomerName as Customer2_1_0_ FROM [Customer] customer0_ WHERE customer0_.CustomerID=@p0;@p0 = 3
2  NHibernate: SELECT orders0_.CustomerID as CustomerID1_, orders0_.OrderID as OrderID1_, orders0_.OrderID as OrderID0_0_, orders0_.ProductNum as ProductNum0_0_, orders0_.CustomerID as CustomerID0_0_ FROM [Order] orders0_ WHERE orders0_.CustomerID=@p0;@p0 = 3
3  NHibernate: Batch commands:
4  command 0:DELETE FROM [Order] WHERE OrderID = @p0;@p0 = 5
5  command 1:DELETE FROM [Order] WHERE OrderID = @p0;@p0 = 6
6 
7  NHibernate: Batch commands:
8  command 0:DELETE FROM [Customer] WHERE CustomerID = @p0;@p0 = 3

 讲到这里,这个inverse="true"算是清楚了,另外就是提醒下大家在分析NH性能的时候,最好使用NHProfiler来做,别跟我一样闷着头浪费很长时间。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12639172/viewspace-663222/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/12639172/viewspace-663222/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值