QueryOver ProjectionList具有不同根实体类型(QueryOver Projec

2019-10-22 02:00发布

我在想重用NHibernate的QueryOvers ProjectionLists问题。 我不能工作了如何再利用的东西不同的根实体。

对象模型被大致表示为:

早餐一对多糕点很多到零或一咖啡

在两个单独的查询是大致为:

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));

这些预测,使用别名,做工精细的第一个查询(根:早餐),因为他们没有试图拉断是对根实体的属性。 在第二个查询(根:咖啡),它爆炸说,它不能找到“coffee.Name”的咖啡,因为它不喜欢的别名。 该QueryOver(()=>咖啡)语法不帮助,因为它实际上并没有注册“咖啡”作为别名,它只是使用它的类型推断。 哦,该死的,这是问题。 有一个愚蠢的一块是打破别名语法不实际使用的别名版本下的应用基础设施。

第二个查询希望投影的样子:

var projections = Projections.ProjectionList()
    .Add(Projections.Property(() => pastry.Name, () => target.PastryName))
    .Add(Projections.Property<Coffee>(c => c.Name, () => target.CoffeeName));

然而,这是现在第一个查询不兼容。

有没有使这项工作的任何方式,所以我不知道根实体类型是什么能项目属性?

Answer 1:

我认为,所有你需要做的是分配coffee别名在session.QueryOver<Coffee>电话:

Coffee coffee = null;

session.QueryOver<Coffee>(() => coffee)
    /* etc */

下面可能是完全无关,你在做什么,但我想我会包括它的情况下,任何人在写,围绕QueryOver别名通过代码。


我想补充caution--跨越这样的不同的查询重用别名可以是有点危险的话。

NHibernate的获取表达式() => coffee并抓住你从表达式中使用(在这种情况下,别名的名称"coffee" ),然后用它在生成的SQL作为别名。 这意味着,这取决于你的代码是如何组织的,共用的预测一样,这可能打破,如果别名更改。

例如,说你有下面的方法来恢复一些共享的预测:

public ProjectionList GetSharedProjections()
{
    Coffee coffee = null;
    TargetDTO target;

    var projections = Projections.ProjectionList()
        .Add(Projections.Property(() => coffee.CoffeeName)
            .WithAlias(() => target.CoffeeName));

    return projections;
}

然后,你有一些代码调用您的helper方法:

session.QueryOver<Coffee>(() => coffee)
    .Select(GetSharedProjections());

只要你的别名匹配一切都会fine--。 第二个改变任何人的任何别名不过,查询将失败。

你也许会在一个别名,以这样的方法来传递:

public ProjectionList GetSharedProjections(Coffee coffeeAlias)
{
    /* Same as above except with "coffeeAlias"
}

然后通过在您的别名:

session.QueryOver<Coffee>(() => coffee)
    .Select(GetSharedProjections(coffee));

但是,这不会工作。 请记住,NHibernate的被抓别名的名称,并直接在生成的SQL使用它。 上面的代码将尝试同时使用"coffee""coffeeAlias"在生成的SQL和会失败。

正确地做到这一点的方法之一(不只是希望没有人改变别名)是通过各地的表情和使用那些具有正确别名重建属性名称。

你会创建一个使用别名和属性构建属性访问一个辅助方法:

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));

当有人改变你的别名,你覆盖。 您也可以放心地使用许多查询中这种方法而不用担心别名变量的名称实际上是。

免责声明:以下是我的个人博客的链接

你可以找到关于建设QueryOver查询,这种方式的详细信息在这里 。



文章来源: QueryOver ProjectionList with different root entity types