2010-02-26 6 views
3

J'ai un projet d'application d'affaires Silverlight mis en place, avec ces codes.NHibernate.Linq, services WCF RIA, erreur bizarre

J'ai cette classe de domaine:

public class BaseDomain 
{ 
    public virtual Guid Id { get; set; } 
    public virtual DateTime CreatedOn { get; set; } 
} 

public class Sector : BaseDomain 
{ 
    public virtual string Code { get; set; } 
    public virtual string Name { get; set; } 
} 

Le domaine des objets mapping a été mis en place et fonctionne bien.

Le J'ai cette classe DTO:

public class SectorDto : BaseDto 
{ 
    [Key] 
    public virtual Guid Id { get; set; } 
    public virtual DateTime CreatedOn { get; set; } 
    public virtual string Code { get; set; } 
    public virtual string Name { get; set; } 

    public SectorDto() 
    { 
    } 

    public SectorDto(Sector d) 
    { 
     Id = d.Id; 
     CreatedOn = d.CreatedOn; 
     Code = d.Code; 
     Name = d.Name; 
    } 
} 

DTO est utilisé pour aplatir l'objet et assurez-vous pas de relations inutiles d'être sérialisés et transféré sur le fil.

Alors j'ai ce RIA DomainService (il existe plusieurs variantes de la méthode GetSectors(), je vous expliquerai plus tard):

[EnableClientAccess] 
public class OrganizationService : BaseDomainService 
{ 
    public IQueryable<SectorDto> GetSectors1() 
    { 
     return GetSession().Linq<Sector>() 
       .Select(x => Mapper.Map<Sector, SectorDto>(x)); 
    } 

    public IQueryable<SectorDto> GetSectors2() 
    { 
     return GetSession().Linq<Sector>().ToList() 
       .Select(x => new SectorDto(x)).AsQueryable(); 
    } 

    public IQueryable<SectorDto> GetSectors3() 
    { 
     return GetSession().Linq<Sector>().Select(x => new SectorDto(x)); 
    } 

    public IQueryable<SectorDto> GetSectors4() 
    { 
     return GetSession().Linq<Sector>().Select(x => new SectorDto() { 
      Id = x.Id, CreatedOn = x.CreatedOn, Name = x.Name, Code = x.Code }); 
    } 
} 

BaseDomainService est juste une classe parent qui fournit le traitement pour la session NHibernate. Je mets la session à vivre par requête web.

Puis je brancher le service à un DataGrid (Silverlight Toolkit) dans une page XAML:

var ctx = new App.Web.Services.OrganizationContext(); 
SectorGrid.ItemsSource = ctx.SectorDtos; 
ctx.Load(s.GetSectors1Query()); 

Lorsque vous appelez les différentes méthodes, j'ai ces résultats:

  1. Méthode GetSectors1 ( génère une exception "L'opération de chargement a échoué pour la requête 'GetSectors1'. Impossible de convertir l'objet de type NHibernate.Linq.Expressions.EntityExpression 'en type' NHibernate.Linq.Expressions.CollectionAccessExpression '. ".

    C'est la meilleure façon que j'essaie de faire. Je veux utiliser la bibliothèque AutoMapper pour mapper automatiquement la classe de domaine au DTO. Je suis assez positif que le problème ne provient pas de l'AutoMapper puisque j'obtiens aussi l'erreur si j'appelle une méthode de la méthode anonyme passée dans Select, par exemple. GetSession().Linq<Sector>().Select(x => CustomMap(x)).

  2. Méthode GetSectors2() affiche les données correctement de la grille, mais cela va à l'encontre du but d'utiliser IQueryable, l'appel ne serait pas paresseux évalué.

  3. La méthode GetSectors3() récupère les données, mais uniquement l'ID et le CreatedOn qui se trouvent dans la classe parente BaseDomain. Le code et le nom sont tous les deux null.

  4. La méthode GetSectors4() récupère les données correctement et paresseusement évalué, mais je ne veux pas mapper manuellement mon domaine à DTO chaque fois comme ça!

Alors qu'est-ce qui donne? Les résultats sont si loin que ce que j'attendais! Une idée sur la façon de faire ce travail? Aucun conseil?

J'apprécie toute aide, je suis presque perdu. Merci beaucoup.

+0

Avez-vous essayé d'utiliser HQL ou l'API Criteria au lieu de Linq? Est-ce que ça marche alors? –

+1

J'ai besoin de LINQ pour obtenir le résultat comme IQueryable, afin que le contrôle RIA Service DomainDataSource puisse gérer automatiquement la pagination, le filtrage, le tri, etc. – Ikhwan

+0

Avez-vous essayé le fournisseur Linq dans le tronc NHibernate (par rapport au fournisseur NHContrib Linq que vous utilisez? à présent)? –

Répondre

0

Eh bien, une chose que vous pouvez faire pour rendre les choses plus simples est séparé l'expression de sélection:

Par exemple:

public Expression<Func<Sector,SectorDto>> EntityToDto = 
     x => new SectorDto 
      { 
       Id = d.Id; 
       CreatedOn = d.CreatedOn; 
       Code = d.Code; 
       Name = d.Name; 
      }; 

Et puis l'utiliser comme:

public IQueryable<SectorDto> GetSectors4() 
    { 
     return GetSession().Linq<Sector>().Select(EntityToDto); 
    } 

Vous pouvez définir ce meth od à l'intérieur du Dto. Btw, il est principalement appelé modèle de présentation lors de son utilisation dans les services RIA, juste à des fins de recherche :). Je n'ai pas encore essayé (j'ai trouvé votre question en cherchant les mêmes réponses que vous, mais votre question m'a fait réfléchir) mais je ne vois pas pourquoi cela ne marcherait pas. De plus, j'utilise beaucoup de génération de code dans le processus, donc je viens de générer cette partie. J'espère que cela t'aides!

0

La raison pour laquelle vous obtenez ces exceptions lors de l'utilisation de méthodes personnalisées à l'intérieur des instructions select avant d'appeler .ToList() est que NHibernate n'a aucun moyen de convertir ces méthodes en SQL. Nhibernate tente de convertir votre instruction LINQ avec votre select en SQL lorsque vous appelez .ToList(). Il ne peut pas convertir votre code automapper en SQL (qui est dans la déclaration select). C'est pourquoi vous devez d'abord sélectionner l'objet dans la base de données, puis appeler .ToList() pour exécuter le SQL, puis parcourir à nouveau la liste et la mapper.