2

J'ai ce mapping NHibernate Fluent:NHibernate - aller chercher à terme

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

Pour résumer:

  1. perte a beaucoup de paiements, les réserves et les états
  2. Paiement a une réserve

J'essaie d'aller chercher des Pertes et leurs paiements et réserves (mais pas les statuts) avec le suivant les contraintes de l'aile:

  1. Seules les pertes qui vont chercher ont au moins un statut avec « status.Status pas (1,2,7) ».
  2. extraient que Loss.Payments où "loss.Payment.Type = 2 et loss.Payment.Reserve.Status! = 4)"
  3. extraient que Loss.Reserves où Reserve.Status! = 3

comme je suis en train de chercher 2 relations parallèles, je dois utiliser multiqueries ou à terme pour éviter le produit cartésien (droit?), comme expliqué ici: http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate

je suis venu avec cette requête (en 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(); 

Cependant, lors de l'exécution de cette requête, j'obtiens une erreur: NHibernate.HibernateException: Impossible d'exécuter la requête multiple [.. requête SQL] ---> System.ArgumentException: La valeur "System.Object []" n'est pas de type " Entities.Loss "et ne peut pas être utilisé dans cette collection générique.

Des indices sur ce que je fais mal ici?

Lorsque je supprime la contrainte d'état, la requête fonctionne:

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

Cependant, les résultats ne sont pas ce que je veux (je dois cette contrainte).

Un conseil? Oh, et l'utilisation de HQL n'est pas un "must", si cela est possible avec Linq ou QueryOver, cela ne me pose aucun problème.

Merci!

Répondre

1

Vous avez une jointure mais vous n'avez pas spécifié l'objet que vous voulez donc vous récupérez en réalité un tuple.

Vous devez spécifier les entités/propriétés que vous voulez dans la sélection, par exemple:

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 

Vous devez également noter que lorsque vous utilisez un vous joindre pouvez obtenir plusieurs résultats pour la même entité, si vous ne voulez unique, entités que vous devez utiliser Transformers.DistinctRootEntity

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

+0

est-il un moyen de faire le même genre de projet ion en utilisant l'API NHibernate LINQ? –

+0

Je n'utilise pas linq donc je ne suis pas sûr, bien que cela semble être ce que vous voulez http://stackoverflow.com/questions/796889/nhibernate-linq-and-distinctrootentity –

0

Je n'ai pas tendance à utiliser HQL, donc je ne peux pas vraiment vous en parler mais je ne suis pas sûr que la requête ci-dessus corresponde exactement à ce que vous voulez. Voulez-vous récupérer toutes les pertes indépendamment des critères sur les objets enfants? La requête ci-dessus ne renvoie que les pertes qui répondent aux critères définis sur les objets enfants. Il semble que vous souhaitiez renvoyer toutes les pertes correspondant aux critères principaux, mais filtrer les collections enfants sur celles-ci? J'entends par là que, compte tenu de la requête en cours, si vous avez une perte qui a un statut 2 mais qui n'a pas de paiements avec le type de paiement 2, l'entité de perte ne sera pas renvoyée par la requête. Au lieu de cela, je pense que vous devez appliquer le filtre sur la jointure afin que l'entité de perte soit renvoyée à partir de la requête, mais la collection de paiement est vide. Par exemple quelque chose comme ceci pour la première requête:

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

Les critères sur l'association des réserves seront ajoutées à la clause de jointure externe gauche signifie que cette relation a le filtre appliqué.

Pour la deuxième requête, vous avez besoin de quelque chose de similaire mais je ne suis pas sûr que vous puissiez mettre des contraintes d'une autre table dans la jointure externe gauche (Payment.Reserve.Status! = 4). Pour cela, vous pouvez utiliser une sous-requête. Quelque chose comme:

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

Je n'ai pas exécuté ces derniers mais je pense que cela devrait vous donner ce que vous voulez.

Questions connexes