说说NHibernate any 标签的用法及查询
来自于一个我自己做着玩的项目 http://ornamentframework.googlecode.com/svn/trunk,里面有个关于用Any标签的例子。类关系如下:
Info:信息对象
InfoReader:信息的读者
IPerformer: 用户标示Info能够被那些用户读取的。
Org、UserGroup、Role、User:组织单元。继承IPerformer,也就是Info.Readers的读者了之一。
由于Org,UserGroup,Role,User之间也有复杂的关系,如果用3中继承方式,不但有速度的问题,而且在SaveOrUpdate中的Cascade也非常难处理,因此他们虽然都继承了IPerformer,但是在Mapping之中却是一点关系都没有。但是Info.Readers的Mapping应该怎样处理呢?首先看InfoReader的Reader,如下:
/// <summary> /// Gets or sets Reader /// </summary> public virtual IPerformer Reader { get; private set; }
然后重点是Mapping
<any name="Reader" meta-type="String" id-type="Guid" > <meta-value class="Ornament.MemberShip.User,Ornament.MemberShip.Core" value="Users" /> <meta-value class="Ornament.MemberShip.UserGroup,Ornament.MemberShip.Core" value="UserGroups"/> <meta-value class="Ornament.MemberShip.Role,Ornament.MemberShip.Core" value="Roles"/> <meta-value class="Ornament.MemberShip.Org,Ornament.MemberShip.Core" value="Orgs" /> <column name="ReaderType" length="20"/> <column name="ReaderId"/> </any>
Any 属性中 Meta-type=”String” 对应是 <meta-value class="Ornament.MemberShip.User,Ornament.MemberShip.Core" value="Users" /> 中的 Value, 即”Users”这个值,说明使用字符串。
id-type 就是下面所有对应的User/Ug/Role/Org的Id类型,他们都是Guid类型。然后下面就是个类型的meta-value标签,这个标签一定要出现在 Column标签之前,否则会报错,接下来,就是meta-type和id-Type
对应的Column名称,也是有顺序的,第一个对应是meta-type,第二个是id-type。
使用SaveOrUpdate的结果如下:
插入,删除,更新都是小事,后来搞了老半天的查询才是关键.
原以为NH很智能,写了下面这个代码,我高估了NH,根本无法查到数据,永远返回0条数据。
DetachedCriteria cri = DetachedCriteria.For<Info>() .Add(Restrictions.In(“Reader”,User1,User2,Role1,Role2,ug1,ug2,org1,org2));
后来按照类型分开Restrictions.In就可以正确查询了。
Any标记的好处非常明显,这个就不说了,但是他是有限制的,在新版本Nh2.02之后(1.2做过,是可以的),妄想把id-type=”String”,从而兼容所有Id类型的object,可以歇歇了。至少在SQLServer 2005中是不行了,不过SQLLite没有问题,其他的还没有测试。异常如下
[InvalidCastException: 对象必须实现 IConvertible。] System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) +7601433 System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType) +4874600 [InvalidCastException: 将参数值从 Guid 转换到 String 失败。] System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType) +4874287 System.Data.SqlClient.SqlParameter.GetCoercedValue() +32 System.Data.SqlClient.SqlParameter.Validate(Int32 index, Boolean isCommandProc) +100 System.Data.SqlClient.SqlCommand.BuildParamList(TdsParser parser, SqlParameterCollection parameters) +203 System.Data.SqlClient.SqlCommand.BuildExecuteSql(CommandBehavior behavior, String commandText, SqlParameterCollection parameters, _SqlRPC& rpc) +237 System.Data.SqlClient.SqlCommand.AddBatchCommand(String commandText, SqlParameterCollection parameters, CommandType cmdType) +94 System.Data.SqlClient.SqlCommandSet.ExecuteNonQuery() +255 NHibernate.AdoNet.SqlClientSqlCommandSet.ExecuteNonQuery() +62