[NHibernate]用一个实体类对应多个数据库表(二)

上一次我们看到了如何让NHibernate通过写多个mapping“半自动”的实现我们动态映射的需求。

这一次我们看一下如何实现多对一之类的关系,以及如何存取数据。

1 两张XXX表存在多对一之类关系时的映射

  由于只指定Class,NHibernate还是不知道该Class具体应该映射到哪张表,于是需要同样的指定entity name

ExpandedBlockStart.gif 代码
   < class  name ="ChildHistoryEntity"  entity-name ="MFSChildHistoryEntity"  table ="tblMFSChildHistories" >
    
< id  name ="Id"  type ="Guid"  column ="uidChildHistoryKey" >
      
< generator  class ="guid.comb" />
    
</ id >
    ...
    
< many-to-one  name ="Child"  class ="ChildEntity"  entity-name ="MFSChildEntity"  column ="uidChildKey"  not-null ="true" />
    ...
  
</ class >

 

2 如何Save或者Update对象

  NHibernate的ISession接口提供了Save(Update等方法同样)的重载方法,可以指定entity name

  但是由于我们已经在Interceptor中拦截了GetEntityName方法,所以这里我们可以像以前一样调用ISession.Save(object entity) 

3 如何检索对象

  由于检索的时候NHibernate无法由类名直接推知表名了,所以我们必须手动的指定entity name了

  在使用ISession.Load的时候我们需要使用ISession.Load(string entityName, object id)方法

  在使用Criteria的时候,我们需要在CreateCriteria的时候传入entityName

  在使用HQL的时候,我们也需要从原来的from ClassName变为from EntityName

 

大概就是这样吧。

接下来的研究方向是通过一套模板的mapping自动生成各个可能的XXX专用mapping,大概思路就是把那些xml反序列化,然后Clone出来几份,replace一些东西之后再序列化,准备接下来看看NHibernate的源码,看看它的hbm2ddl里面有没有什么现成可用的东西~~

 

UPDATE:HQL貌似行不通,至少我还没有找到解决之道。具体如下

忽然发现一个问题:以下的UT代码,忽然发现跑不通了

ExpandedBlockStart.gif 代码
        [Test]
        
public   void  SaveChild()
        {
            var child  =   new  ChildEntity
                            {
                                IdNo  =   " S1234567D " ,
                                IdType  =  ChildIdType.NRIC,
                                ...
                            };
            ChildDAO.Save(child);
            
            Assert.AreNotEqual(Guid.Empty, child.Id);
            Assert.IsNotNull(LoadByIdTypeAndNo(child.Centre.BU, child.IdType, child.IdNo));
        }

        
public  ChildEntity LoadByIdTypeAndNo( string  bu, ChildIdType idType,  string  idNo)
        {
            
return  ChildDAO.FindByIdTypeAndNo(bu, idType, idNo);
        }

 

看了一下NH生成出的sql,吓了一跳 

ExpandedBlockStart.gif 代码
NHibernate:  INSERT   INTO  tblMFSChildren ...
NHibernate:  select  ...  from  tblMFSChildren mfschilden0_  where  mfschilden0_.chrIdType = @p0   and  mfschilden0_.strIdNo = @p1 ; @p0   =   ' N ' @p1   =   ' S1234567D '
NHibernate:  select  ... from  tblCCChildren ccchildent0_  where  ccchildent0_.chrIdType = @p0   and  ccchildent0_.strIdNo = @p1 ; @p0   =   ' N ' @p1   =   ' S1234567D '
NHibernate:  select  ...  from  tblLSHChildren lshchilden0_  where  lshchilden0_.chrIdType = @p0   and  lshchilden0_.strIdNo = @p1 ; @p0   =   ' N ' @p1   =   ' S1234567D '

 

这其中MFS、CC、LSH是我的XXX的三种可能的取值

回头看一下DAO的写法,并没有select三个表

ExpandedBlockStart.gif 代码
         public  ChildEntity FindByIdTypeAndNo(string bu, ChildIdType idType, string idNo)
        {
            
var  query  =  string.Format(" select  c  from  { 0 }ChildEntity  as  c  where  c.ChrIdType = :idType  and  c.IdNo = :idNo", bu);
            
return  Session.CreateQuery(query)
                
// .SetEnum("idType", idType)
                .SetCharacter("idType", ( char )idType)
                .SetAnsiString("idNo", idNo)
                .SetMaxResults( 1 )
                .UniqueResult < ChildEntity > ();

        }

 

回想一下从上次跑通UT到现在UT失败,做过的工作正是把mapping从一份(MFS)增加到了上述的三份(关于如何做到这一点还请期待下文)。

于是问题大概出在NH在翻译HQL的时候,把from entityName的部分首先翻译成了className,然后发现有三个entity对应着同一个className,于是生成出三条sql语句。但是如果直接指定成from className的话,又会报错说没有className对应的mapping。

找了半天IQuery的方法,也没有什么能够手动指定entityName的地方,无奈放弃HQL。。。哪位知道方法还望不吝赐教 

不过反正也早就瞅HQL不顺眼了~~又不能获得编译器的检查,又容易写错(例如少写一个空格之类的)。但是Criteria API我还是不会用(这玩意可读性也太差了吧。。。)没关系,祭出早就想试一试的LinqToNhibernate~~

ExpandedBlockStart.gif 代码
         public  ChildEntity FindByIdTypeAndNo( string  bu, ChildIdType idType,  string  idNo)
        {
            
return  Session.Linq < ChildEntity > (bu  +  ChildEntity.StaticEntityClassName)
                .Where(child 
=>  child.ChrIdType  ==  ( char )idType
                                
&&  child.IdNo.Equals(idNo, StringComparison.OrdinalIgnoreCase))
                .FirstOrDefault();
        }

 

恩~~简单顺眼~~UT的结果也正确,就是不知性能如何~~~~以后再说吧~咳咳~~

P.S.1 ChrIdType本来在我的ChildEntity是protect virtual的因为我不希望外接能直接操作这个char字段,而是希望通过一个枚举来访问,但是现在不得不public出来了。解决办法么,一个是考虑到.Net世界里印象中提供一种FriendsAssembly机制可以让我的DAO的Assembly内部访问ModelAssembly中的类的internal字段,可以用这种方法解决(话说我都想吐槽我自己了,上述所说都是在正常的良好分层的架构下的考虑,而这次应客户的要求DAO(包括interface和impl)和Model是定义在同一个叫做DataAccess的Assembly,只需要protect internal就可以了(光internal还不行,NH不干)。。。客户要求多原来还有这种好处orz)。另一个更好的方向是直接使用NH提供的EnumStringType,这个今天刚看到,还没有尝试。

P.S.2 在初次使用LinqToNhibernate的时候发现NHibernate.Linq.dll竟然没有强命名,这是何等的师太= = 

Google了一下,找到Signer这个东西,给创建出的新的强命名过的dll就好了

 

最后吐槽一下Nhibernate,官方网站上挂的那个说明文档太老了吧!NH 2.1的特性就没怎么提啊~~~ 

转载于:https://www.cnblogs.com/jiaxingseng/archive/2010/07/14/1777465.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值