3

我有这个 Fluent NHibernate 映射:

public LossMap()
{
    Table("losses");
    Id(x => x.Id).Column("id");
    References(x => x.Policy).Column("pol_id");
    HasMany(x => x.Statuses).KeyColumn("loss_id").Cascade.All().Inverse();
    HasMany(x => x.Reserves).KeyColumn("loss_id").Cascade.All().Inverse();
    HasMany(x => x.Payments).KeyColumn("loss_id").Cascade.All().Inverse();
}

public LossPaymentMap()
{
    Table("losspayments");
    Id(x => x.Id).Column("id");
    Map(x => x.Type).Column("type_id");
    References(x => x.Reserve).Column("reserve_id");
}

public LossReserveMap()
{
    Table("lossreserves");
    Id(x => x.Id).Column("id");
    Map(x => x.Type).Column("type_id");
    Map(x => x.Status).Column("status_id");
    References(x => x.ParentReserve).Column("parent_reserve_id");
}

public LossStatusMap()
{
    Table("lossstatuses");
    Id(x => x.Id).Column("id");
    Map(x => x.Status).Column("status_id");
    Map(x => x.ExpirationDate).Column("expirationdate");
    References(x => x.Loss).Column("loss_id");
}

总结一下:

  1. 损失有许多付款、准备金和状态
  2. 付款有一个储备

我正在尝试获取具有以下约束的损失及其付款和准备金(但不是状态):

  1. 仅获取至少具有“status.Status not in (1,2,7)”状态的损失。
  2. 仅获取“loss.Payment.Type = 2 and loss.Payment.Reserve.Status != 4)”的 Loss.Payments
  3. 仅在 Reserve.Status != 3 处获取 Loss.Reserves

当我试图获取 2 个并行关系时,我必须使用多查询或期货来避免笛卡尔积(对吗?),如下所述:http: //ayende.com/blog/4367/eagerly-loading-entity-associations-高效地休眠

我想出了这个查询(在 HQL 中):

int[] statuslist = new int[3] {1, 2, 7};

var losses =
session.CreateQuery(
    "from Loss l left join fetch l.Payments as payment join l.Statuses as status where l.Policy.Product.Id = :tid1 " + 
    "and status.Status not in ( :statuslist1) " +
    "and payment.Type = 2 and payment.Reserve.Status != 4")
    .SetParameter("tid1", productid)
    .SetParameterList("statuslist1", statuslist)
    .Future<Loss>();

session.CreateQuery(
    "from Loss l left join fetch l.Reserves as reserve join l.Statuses as status where l.Policy.Product.Id = :tid2 " +
    "and status.Status not in ( :statuslist2) " +
    "and reserve.Status != 3 ")
    .SetParameter("tid2", productid)
    .SetParameterList("statuslist2", statuslist)
    .Future<Loss>();

var list = losses.ToList();

但是,执行此查询时,出现错误:NHibernate.HibernateException: Failed to execute multi query[..SQL query]---> System.ArgumentException: The value "System.Object[]" is not of type "Entities .Loss”并且不能在这个通用集合中使用。

任何线索我在这里做错了什么?

当我删除状态约束时,查询有效:

var losses =
session.CreateQuery(
    "from Loss l left join fetch l.Payments as payment where l.Policy.Product.Id = :tid1 " + 
    "and payment.Type = 2 and payment.Reserve.Status != 4")
    .SetParameter("tid1", productid)
    .Future<Loss>();

session.CreateQuery(
    "from Loss l left join fetch l.Reserves as reserve where l.Policy.Product.Id = :tid2 " +
    "and reserve.Status != 3 ")
    .SetParameter("tid2", productid)
    .Future<Loss>();

但是,结果不是我想要的(我需要那个约束)。

有什么建议吗?

哦,使用 HQL 不是“必须的”,如果可以使用 Linq 或 QueryOver,我对此没有任何问题。

谢谢!

4

2 回答 2

1

你有一个连接,但没有指定你想要的对象,因此你实际上得到了一个元组。

您应该在选择中指定您想要的实体/属性,例如:

select l
from Loss l left join fetch l.Payments as payment
where l.Policy.Product.Id = :tid1
and payment.Type = 2 and payment.Reserve.Status != 4

您还应该注意,使用连接时,您可以获得同一实体的多个结果,如果您只想要唯一的实体,您应该使用Transformers.DistinctRootEntity

对于 IQuery/ICriteria:.SetResultTransformer(Transformers.DistinctRootEntity)
对于 QueryOver:.TransformUsing(Transformers.DistinctRootEntity)

于 2011-10-11T11:35:08.100 回答
0

我不倾向于使用 HQL,因此无法对此提供真正的建议,但我不确定上面的查询是否正是您想要的。无论子对象的标准如何,您都想获取所有损失吗?上面的查询将只返回满足子对象上设置的标准的损失。看起来您想返回与主要标准匹配的所有损失,但过滤那些子集合?我的意思是,在给定当前查询的情况下,如果您的损失为状态 2,但没有支付类型为 2 的付款,则查询不会返回损失实体。相反,我认为您需要在联接上应用过滤器,以便从查询中返回损失实体,但付款集合为空。例如,第一个查询是这样的:

int[] values = new int[] { 1,2,3};
var query1 = session.CreateCriteria<Trade>()
                    .CreateAlias("Status", "s").Add(Expression.Not(Expression.In("s.Status", values)))
                    .CreateAlias("Reserves", "r", JoinType.LeftOuterJoin, Expression.Not(Expression.Eq("r.Status", 3)));

Reserves 关联的条件将添加到左外连接子句,这意味着只有该关系应用了过滤器。

对于第二个查询,您需要类似的东西,但我不确定您是否可以将来自另一个表的约束放入左外连接(Payment.Reserve.Status != 4)。为此,您可以使用子查询。就像是:

DetachedCriteria paymentSubQuery = null; //make a query for getting all payments with type 2 and reserve.Status != 4

var query2 = session.CreateCriteria<Trade>()
                    .CreateAlias("Status", "s").Add(Expression.Not(Expression.In("s.Status", values)))
                    .CreateAlias("Payments", "p", JoinType.LeftOuterJoin).Add(Subqueries.PropertyIn("p.Id", paymentSubQuery));

我实际上并没有运行这些,但我认为这应该大致给你你想要的。

于 2011-10-06T11:53:26.700 回答