2010-10-13 8 views
2

J'ai utilisé Nhibernate avec LINQ un peu maintenant et j'ai quelques problèmes. Dire que j'ai les entités suivantes:NHibernate - LINQ Limitations

public class User 
{ 
    public virtual int UserID { get; set; } 
    public virtual bool IsActive { get; set; } 
    public virtual bool SomeField { get { return 0; } } 
    public virtual DateTime DateRegistered { get; set; } 
    public virtual IList<Membership> Membership { get; set; } 
    public virtual Membership ValidMembership { get { return Membership.FirstOrDefault(m => m.IsValid); } } 
} 

public class User2 
{ 
    public virtual int UserID { get; set; } 
    public virtual int MembershipID { get; set; } 
} 

public class Membership 
{ 
    public virtual int MembershipID { get; set; } 
    public virtual bool IsValid { get; set; } 
} 

Maintenant, si je lance la requête suivante:

var users = service.Linq<User>() 
    .Where(u => u.IsActive) // This would work 
    .Where(u => u.SomeField > 0) // This would fail (i know i can map these using formulas but this is here to illustrate) 
    .Where(u => u.Membership.Any(m => m.IsValid)) // This would work 
    .Where(u => u.ValidMembership != null) // This would fail 
    .Where(u => u.DateRegistered > DateTime.UtcNow.AddDays(-1)) // This would work 
    .Where(u => u.DateRegistered.AddDays(1) > DateTime.UtcNow) // This would fail 
    .Select(u => new User2 { UserID = u.UserID }) // This would work 
    .Select(u => u.UserID) // This would work 
    .Select(u => new { UserID = u.UserID }) // This would fail 
    .Select(u => new User2 { UserID = u.UserID, MembershipID = u.Membership.Any(m => m.IsValid) ? u.Membership.Any(m => m.IsValid).First().MembershipID : 0 }); // This would fail 

J'ai ajouté un commentaire à côté de chacun à indiqué qu'ils travailleraient ou échouer. Ce sont les scénarios auxquels je peux penser en ce moment. J'ai réussi à surmonter ces problèmes en convertissant les données en liste avant de devoir faire quelque chose de trop sophistiqué. Cela a évidemment un impact sur les performances. Je me demandais si les futures versions du fournisseur LINQ pour NHibernate les supporteraient? Aussi, quelqu'un sait-il comment le cadre d'entité pourrait gérer ces scénarios. J'imagine que le cadre de l'entité serait une amélioration, mais je ne veux pas sauter en bateau si les mêmes problèmes existent.

Appréciez vos commentaires. Merci

+1

Pourriez-vous fournir un échantillon de vous convertir les données en une liste avant de faire les choses de fantaisie? Pour le moment, je ne suis pas vraiment sûr de votre question. – Gage

+0

Salut, fondamentalement, je filtrais les données autant que possible, puis en ajoutant .ToList() avant d'enchaîner plus loin les clauses/select. Cela signifie que moins de travail est fait en mémoire. – nfplee

Répondre

3

NHibernate 3 prend en charge plus de constructions que le fournisseur de contrib que vous utilisez (Beta1 vient de sortir, la version finale est attendue avant la fin de l'année)

Cependant, comme d'autres l'ont souligné, certaines constructions sont difficiles (ou impossible) pour analyser, tandis que d'autres nécessitent un code très spécifique pour traduire les arbres d'expression en SQL.

Heureusement, le nouveau fournisseur est également extensible, ce qui signifie que vous pouvez ajouter votre propre logique db pour vos propres méthodes, ou qui ne sont pas prises en charge.

+0

Salut, merci pour votre réponse. Je suis impatient de v3. Actuellement, j'ai ajouté un commentaire indiquant où j'ai appliqué un hack (converti en une liste). 99% du temps je peux contourner les limites que j'ai trouvées mais c'est souvent des choses comme des rapports qui causent des problèmes où la performance n'est pas vraiment un problème. – nfplee

0

Entity Framework échouera dans les mêmes cas que NHibernate (au moins pour vos exemples). Rappelez-vous, Linq utilise le chargement différé pour les opérations Where() - et tout dans Linq2SQL (Entity Framework inclus) et Linq2NHibernate doit être traduit en SQL dans le chargement différé. Les appels de méthode ne peuvent pas être convertis en SQL - il n'y a aucune représentation de la méthode dans SQL - et c'est pourquoi il échouerait. Lorsque vous ToList() - vous forcez les instructions Linq précédentes à évaluer (à un appel de base de données) et ensuite à travailler vers l'avant, vous travaillez sur une représentation en mémoire vous permettant d'utiliser les arbres d'expression Linq2Object complets (qui ont la possibilité d'appeler des méthodes de fantaisie, etc.)

En ce qui concerne vos projections - je n'utiliserais pas Linq2NHibernate pour celles-ci - mais utiliser plutôt les projections intégrées à NHibernate 'standard'.

1

Ce code ne doit même pas être compilé. User.SomeField est une propriété booléenne mais vous essayez de renvoyer 0 à partir du getter? SomeField et ValidMemberships ne devraient même pas être virtuels car ce sont des champs qui ne seraient même pas gérés par NHibernate.

+0

Salut désolé j'ai écrit cet échantillon de la mémoire et accidentellement avoir quelques fautes de frappe, mais vous avez l'idée. – nfplee

1

C'est un ajout à la réponse de Diego Mijelshon

  • Propriétés calculées ne peut jamais être analysé par un fournisseur Linq hors de la boîte, parce que les corps de méthode ne peuvent pas être convertis en un arbre d'expression.
  • Certains ou peut-être même tous les problèmes non implémentés sont implémentés dans le fournisseur Linq actuel.

    Où (u => u.SomeField> 0) // propriété calculée somefield

    Où (u => u.ValidMembership!= null) // Propriété calculée ValidMembership

    Où (u => u.DateRegistered.AddDays (1)> DateTime.UtcNow) // La méthode DateTime.AddDays n'est pas implémentée pour ce côté de l'opérateur de comparaison de date supérieur à >

    Select (u => new {userid = u.UserID}) // Création d'objets anonymes ne sont pas mis en œuvre

    Select (u => new Utilisateur2 {userid = u.UserID, MembershipID = u. Membership.Any (m => m.IsValid)? U.Membership.Any (m => m.IsValid) .First(). MembershipID: 0}); // Opérateur ternaire non implémenté