Basically, i have been trying to do this (count distinct based on two columns):
基本上,我一直在尝试这样做(根据两栏分别计算):
select count(distinct(checksum(TableA.PropertyA, TableB.PropertyB)))
from TableA
left outer join TableB
on TableA.TableBId = TableB.Id
where PropertyA like '%123%'
Been googling on how to do this but with no luck. Tried this, but never actually worked. This does not count distinctly based on the two properties from two tables:
一直在谷歌上搜索如何做这个,但没有运气。试过了,但没有成功。根据两张表的两个属性,这并不算清楚:
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 个解决方案
#1
6
Okay this is going to take a few steps, so bear with me. I'm assuming SQL server here, but the instructions should work for any dialect that supports checksum
1:
好吧,这将采取一些步骤,请耐心等待。我假设这里是SQL server,但是指令应该适用于任何支持checksum1的方言:
-
Create a custom dialect that supports the
checksum
function:创建支持校验和功能的自定义方言:
public class MyCustomDialect : MsSql2008Dialect { public MyCustomDialect() { RegisterFunction("checksum", new SQLFunctionTemplate(NHibernateUtil.Int32, "checksum(?1, ?2)")); } }
-
Update your configuration to use the custom dialect (you can do this either in your configuration XML file or with code. See this answer for more information). Here's how I did it inside of my existing configuration code:
更新您的配置以使用自定义方言(您可以在配置XML文件中或在代码中实现这一点)。更多信息请参见此答案)。以下是我在现有配置代码中的做法:
configuration .Configure(@"hibernate.cfg.xml") .DataBaseIntegration( db => db.Dialect<MyCustomDialect>());
-
Create a custom projection that calls
checksum
. This step is optional-- you can callProjections.SqlFunction
directly if you'd like, but I think refactoring it into a separate function is cleaner:创建一个调用校验和的自定义投影。这一步是可选的——您可以调用投影。如果你愿意的话,可以直接使用SqlFunction,但是我认为将其重构为一个单独的函数是更简洁的:
public static class MyProjections { public static IProjection Checksum(params IProjection[] projections) { return Projections.SqlFunction("checksum", NHibernateUtil.Int32, projections); } }
-
Write your QueryOver query and call the custom projection:
编写您的查询并调用自定义投影:
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>();
This should generate SQL that looks like what you're after:
这应该会生成如下所示的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 */
1Still trying to figure out if there's a way to map a function without manually specifying the number of arguments
#1
6
Okay this is going to take a few steps, so bear with me. I'm assuming SQL server here, but the instructions should work for any dialect that supports checksum
1:
好吧,这将采取一些步骤,请耐心等待。我假设这里是SQL server,但是指令应该适用于任何支持checksum1的方言:
-
Create a custom dialect that supports the
checksum
function:创建支持校验和功能的自定义方言:
public class MyCustomDialect : MsSql2008Dialect { public MyCustomDialect() { RegisterFunction("checksum", new SQLFunctionTemplate(NHibernateUtil.Int32, "checksum(?1, ?2)")); } }
-
Update your configuration to use the custom dialect (you can do this either in your configuration XML file or with code. See this answer for more information). Here's how I did it inside of my existing configuration code:
更新您的配置以使用自定义方言(您可以在配置XML文件中或在代码中实现这一点)。更多信息请参见此答案)。以下是我在现有配置代码中的做法:
configuration .Configure(@"hibernate.cfg.xml") .DataBaseIntegration( db => db.Dialect<MyCustomDialect>());
-
Create a custom projection that calls
checksum
. This step is optional-- you can callProjections.SqlFunction
directly if you'd like, but I think refactoring it into a separate function is cleaner:创建一个调用校验和的自定义投影。这一步是可选的——您可以调用投影。如果你愿意的话,可以直接使用SqlFunction,但是我认为将其重构为一个单独的函数是更简洁的:
public static class MyProjections { public static IProjection Checksum(params IProjection[] projections) { return Projections.SqlFunction("checksum", NHibernateUtil.Int32, projections); } }
-
Write your QueryOver query and call the custom projection:
编写您的查询并调用自定义投影:
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>();
This should generate SQL that looks like what you're after:
这应该会生成如下所示的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 */
1Still trying to figure out if there's a way to map a function without manually specifying the number of arguments