Nhibernate计数不同(基于多列)

时间:2014-02-12 10:34:04

标签: sql nhibernate queryover nhibernate-criteria nhibernate-projections

基本上,我一直在尝试这样做(根据两列计算不同):

select count(distinct(checksum(TableA.PropertyA, TableB.PropertyB))) 
from TableA 
left outer join TableB
on TableA.TableBId = TableB.Id 
where PropertyA like '%123%'

一直在谷歌搜索如何做到这一点,但没有运气。试过这个,但从未真正奏效过。这并不明显基于两个表中的两个属性:

var queryOver = c.QueryOver<TableA>();
TableB tableBAlias = null;
TableA tableAAlias = null;
ProjectionList projections = Projections.ProjectionList();

queryOver.AndRestrictionOn(x => x.PropertyA).IsLike("%123%");
projections.Add(Projections.CountDistinct(() => tableAAlias.PropertyA));

queryOver.JoinAlias(x => x.TableB , () => tableBAlias, JoinType.LeftOuterJoin);
projections.Add(Projections.CountDistinct(() => tableBAlias.PropertyB));

queryOver.Select(projections);
queryOver.UnderlyingCriteria.SetProjection(projections);
return queryOver.TransformUsing(Transformers.DistinctRootEntity).RowCount();

1 个答案:

答案 0 :(得分:7)

好的,这需要几步,所以请耐心等待。我在这里假设SQL服务器,但说明适用于任何支持checksum 1 的方言:

  1. 创建支持checksum功能的自定义方言:

    public class MyCustomDialect : MsSql2008Dialect
    {
        public MyCustomDialect()
        {
            RegisterFunction("checksum", new SQLFunctionTemplate(NHibernateUtil.Int32, "checksum(?1, ?2)"));
        }
    }
    
  2. 更新您的配置以使用自定义方言(您可以在配置XML文件中或使用代码执行此操作。有关详细信息,请参阅this answer)。以下是我在现有配置代码中的使用方法:

    configuration
        .Configure(@"hibernate.cfg.xml")
        .DataBaseIntegration(
            db => db.Dialect<MyCustomDialect>());
    
  3. 创建一个调用checksum的自定义投影。此步骤是可选的 - 如果您愿意,可以直接调用Projections.SqlFunction,但我认为将其重构为单独的函数更简洁:

    public static class MyProjections 
    {
        public static IProjection Checksum(params IProjection[] projections)
        {
            return Projections.SqlFunction("checksum", NHibernateUtil.Int32, projections);   
        }
    }
    
  4. 编写QueryOver查询并调用自定义投影:

    int count = session.QueryOver<TableA>(() => tableAAlias)
        .Where(p => p.PropertyA.IsLike("%123%"))
        .Left.JoinQueryOver(p => p.TableB, () => tableBAlias)
        .Select(
            Projections.Count(
                Projections.Distinct(
                MyProjections.Checksum(
                    Projections.Property(() => tableAAlias.PropertyA),
                    Projections.Property(() => tableBAlias.PropertyB)))))
        .SingleOrDefault<int>();
    

    这应该生成看起来像你所追求的SQL:

    SELECT count(distinct checksum(this_.PropertyA, tableba1_.PropertyB)) as y0_
    FROM   [TableA] this_
        left outer join [TableB] tableba1_
        on this_.TableBId = tableba1_.Id
    WHERE  this_.PropertyA like '%123%' /* @p0 */
    
  5. <小时/> 1 仍试图找出是否有办法在不手动指定参数数量的情况下映射函数