2

我有這個功能NHibernate映射: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不在(1,2,7)」。
  2. 僅取Loss.Payments其中 「loss.Payment.Type = 2和loss.Payment.Reserve.Status!= 4)」
  3. 僅取Loss.Reserves其中Reserve.Status!= 3

當我想取2間平行的關係,我必須使用multiqueries或期貨,以避免笛卡爾乘積(右?),因爲這裏說明:http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate

我想出了這個查詢(在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:無法執行多個查詢[.. SQL查詢] ---> System.ArgumentException:值「System.Object []」不是類型「 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,我沒有問題。

謝謝!

回答

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)

+0

有沒有辦法做同樣項目離子使用NHibernate的LINQ API? – 2012-04-05 16:27:31

+0

我不使用LINQ所以我不確定,雖然這似乎是你想要的東西http://stackoverflow.com/questions/796889/nhibernate-linq-and-distinctrootentity –

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

的儲備協會的標準將被添加到左外連接子句意味着只有擁有相關應用的過濾器。

對於第二個查詢,你需要類似的東西,但我不知道,你可以把限制從另一個表的左外內加入(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)); 

我沒有真正運行這些,但我認爲應該大致給你你想要的。