具有不同根实体类型的 QueryOver ProjectionList
QueryOver ProjectionList with different root entity types
我在尝试在 NHibernate QueryOver 中重用 ProjectionList 时遇到问题。我不知道如何为不同的根实体重用东西。
对象模型大致表示为:
早餐一对多糕点多对零或一咖啡
两个单独的查询大致是:
session.QueryOver<Breakfast>()
.Where(b => b.Id == searchId)
.Inner.JoinQueryOver(b => b.Pastries, () => pastry)
.Left.JoinAlias(p => p.Coffee, () => coffee)
.Select(projections)
.TransformUsing(Transformers.AliasToBean<TargetDto>())
.List<TargetDto>();
session.QueryOver<Coffee>()
.Where(c => c.Id == searchId)
.Inner.JoinQueryOver(c => c.Pastries, () => pastry)
.Select(projections)
.TransformUsing(Transformers.AliasToBean<TargetDto>())
.List<TargetDto>();
我尝试重用的常见投影如下所示:
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => pastry.Name, () => target.PastryName))
.Add(Projections.Property(() => coffee.Name, () => target.CoffeeName));
这些使用别名的投影对于第一个查询(根:Breakfast)工作正常,因为它们不会尝试提取该根实体上的属性。在第二个查询(root:Coffee)中,它爆炸说它无法在 Coffee 上找到 'coffee.Name',因为它不喜欢别名。 QueryOver(() => coffee) 语法没有帮助,因为它实际上并没有将 'coffee' 注册为别名,它只是将其用于类型推断。 天啊见鬼,这就是问题所在。有一个愚蠢的应用程序基础架构破坏了别名语法,实际上不使用下面的别名版本。
第二个查询希望投影看起来像:
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => pastry.Name, () => target.PastryName))
.Add(Projections.Property<Coffee>(c => c.Name, () => target.CoffeeName));
然而,这现在与第一个查询不兼容。
有什么方法可以使这项工作起作用,这样我就可以在不知道根实体类型是什么的情况下投影属性吗?
我认为您需要做的就是在 session.QueryOver<Coffee>
调用中分配 coffee
别名:
Coffee coffee = null;
session.QueryOver<Coffee>(() => coffee)
/* etc */
以下内容可能与您正在做的事情完全无关,但我想我会包括它以防其他人正在编写传递 QueryOver 别名的代码。
我要提醒一句——像这样在不同的查询中重复使用别名可能有点危险。
NHibernate 采用表达式 () => coffee
并从表达式中获取您正在使用的别名的名称(在本例中为 "coffee"
),然后在生成的 SQL 作为别名。这意味着根据您的代码结构,如果别名更改,像这样的共享投影可能会中断。
例如,假设您有以下方法来 return 一些共享投影:
public ProjectionList GetSharedProjections()
{
Coffee coffee = null;
TargetDTO target;
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => coffee.CoffeeName)
.WithAlias(() => target.CoffeeName));
return projections;
}
然后你有一些代码调用你的辅助方法:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections());
一切都会正常进行——只要您的别名匹配。但是,第二个任何人更改其中任何一个别名,查询都会失败。
您可能想将别名传递给这样的方法:
public ProjectionList GetSharedProjections(Coffee coffeeAlias)
{
/* Same as above except with "coffeeAlias"
}
然后传入你的别名:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections(coffee));
但这也行不通。请记住,NHibernate 正在获取别名的名称并直接在生成的 SQL 中使用它。上面的代码将尝试在生成的 SQL 中同时使用 "coffee"
和 "coffeeAlias"
,但会失败。
正确执行此操作的一种方法(不只是希望没有人更改别名)是传递表达式并使用它们来重建具有正确别名的 属性 名称。
您将创建一个辅助方法,使用别名和 属性:
构建 属性 访问
public static PropertyProjection BuildProjection<T>(
Expression<Func<object>> aliasExpression,
Expression<Func<T, object>> propertyExpression)
{
string alias = ExpressionProcessor.FindMemberExpression(aliasExpression.Body);
string property = ExpressionProcessor.FindMemberExpression(propertyExpression.Body);
return Projections.Property(string.Format("{0}.{1}", alias, property));
}
然后,您可以更改 GetSharedProjections
方法以采用表达式形式的别名:
public ProjectionList GetSharedProjection(Expression<Func<Coffee>> coffeeAlias)
{
TargetDTO target = null;
var projections = Projections.ProjectionList()
.Add(BuildProjection<Coffee>(coffeeAlias, c => c.CoffeeName))
.WithAlias(() => target.CoffeeName);
}
现在,调用您的方法如下所示:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections(() => coffee));
当有人更改您的别名时,您就会受到保护。您还可以在许多查询中安全地使用此方法,而不必担心别名变量的实际名称是什么。
免责声明:以下是link转自我的个人博客
您可以通过这种方式找到有关构建 QueryOver 查询的更多信息here。
我在尝试在 NHibernate QueryOver 中重用 ProjectionList 时遇到问题。我不知道如何为不同的根实体重用东西。
对象模型大致表示为:
早餐一对多糕点多对零或一咖啡
两个单独的查询大致是:
session.QueryOver<Breakfast>()
.Where(b => b.Id == searchId)
.Inner.JoinQueryOver(b => b.Pastries, () => pastry)
.Left.JoinAlias(p => p.Coffee, () => coffee)
.Select(projections)
.TransformUsing(Transformers.AliasToBean<TargetDto>())
.List<TargetDto>();
session.QueryOver<Coffee>()
.Where(c => c.Id == searchId)
.Inner.JoinQueryOver(c => c.Pastries, () => pastry)
.Select(projections)
.TransformUsing(Transformers.AliasToBean<TargetDto>())
.List<TargetDto>();
我尝试重用的常见投影如下所示:
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => pastry.Name, () => target.PastryName))
.Add(Projections.Property(() => coffee.Name, () => target.CoffeeName));
这些使用别名的投影对于第一个查询(根:Breakfast)工作正常,因为它们不会尝试提取该根实体上的属性。在第二个查询(root:Coffee)中,它爆炸说它无法在 Coffee 上找到 'coffee.Name',因为它不喜欢别名。 QueryOver(() => coffee) 语法没有帮助,因为它实际上并没有将 'coffee' 注册为别名,它只是将其用于类型推断。 天啊见鬼,这就是问题所在。有一个愚蠢的应用程序基础架构破坏了别名语法,实际上不使用下面的别名版本。
第二个查询希望投影看起来像:
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => pastry.Name, () => target.PastryName))
.Add(Projections.Property<Coffee>(c => c.Name, () => target.CoffeeName));
然而,这现在与第一个查询不兼容。
有什么方法可以使这项工作起作用,这样我就可以在不知道根实体类型是什么的情况下投影属性吗?
我认为您需要做的就是在 session.QueryOver<Coffee>
调用中分配 coffee
别名:
Coffee coffee = null;
session.QueryOver<Coffee>(() => coffee)
/* etc */
以下内容可能与您正在做的事情完全无关,但我想我会包括它以防其他人正在编写传递 QueryOver 别名的代码。
我要提醒一句——像这样在不同的查询中重复使用别名可能有点危险。
NHibernate 采用表达式 () => coffee
并从表达式中获取您正在使用的别名的名称(在本例中为 "coffee"
),然后在生成的 SQL 作为别名。这意味着根据您的代码结构,如果别名更改,像这样的共享投影可能会中断。
例如,假设您有以下方法来 return 一些共享投影:
public ProjectionList GetSharedProjections()
{
Coffee coffee = null;
TargetDTO target;
var projections = Projections.ProjectionList()
.Add(Projections.Property(() => coffee.CoffeeName)
.WithAlias(() => target.CoffeeName));
return projections;
}
然后你有一些代码调用你的辅助方法:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections());
一切都会正常进行——只要您的别名匹配。但是,第二个任何人更改其中任何一个别名,查询都会失败。
您可能想将别名传递给这样的方法:
public ProjectionList GetSharedProjections(Coffee coffeeAlias)
{
/* Same as above except with "coffeeAlias"
}
然后传入你的别名:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections(coffee));
但这也行不通。请记住,NHibernate 正在获取别名的名称并直接在生成的 SQL 中使用它。上面的代码将尝试在生成的 SQL 中同时使用 "coffee"
和 "coffeeAlias"
,但会失败。
正确执行此操作的一种方法(不只是希望没有人更改别名)是传递表达式并使用它们来重建具有正确别名的 属性 名称。
您将创建一个辅助方法,使用别名和 属性:
构建 属性 访问public static PropertyProjection BuildProjection<T>(
Expression<Func<object>> aliasExpression,
Expression<Func<T, object>> propertyExpression)
{
string alias = ExpressionProcessor.FindMemberExpression(aliasExpression.Body);
string property = ExpressionProcessor.FindMemberExpression(propertyExpression.Body);
return Projections.Property(string.Format("{0}.{1}", alias, property));
}
然后,您可以更改 GetSharedProjections
方法以采用表达式形式的别名:
public ProjectionList GetSharedProjection(Expression<Func<Coffee>> coffeeAlias)
{
TargetDTO target = null;
var projections = Projections.ProjectionList()
.Add(BuildProjection<Coffee>(coffeeAlias, c => c.CoffeeName))
.WithAlias(() => target.CoffeeName);
}
现在,调用您的方法如下所示:
session.QueryOver<Coffee>(() => coffee)
.Select(GetSharedProjections(() => coffee));
当有人更改您的别名时,您就会受到保护。您还可以在许多查询中安全地使用此方法,而不必担心别名变量的实际名称是什么。
免责声明:以下是link转自我的个人博客
您可以通过这种方式找到有关构建 QueryOver 查询的更多信息here。