0 votes

Est-il possible d'utiliser des projections Linq avec des méthodes d'extension

Je suis en train d'essayer d'utiliser AutoMapper et un motif de repository avec une interface fluide, et je rencontre des difficultés avec la projection Linq. Pour ce que ça vaut, ce code fonctionne bien lorsque l'on utilise simplement des objets en mémoire. Lorsque l'on utilise un fournisseur de base de données, cependant, ça casse lors de la construction du graphe de requête. J'ai essayé à la fois SubSonic et Linq to SQL avec le même résultat. Merci pour vos idées.

Voici une méthode d'extension utilisée dans tous les scénarios - C'est la source du problème car tout fonctionne bien sans utiliser de méthodes d'extension

public static IQueryable ByName(this IQueryable users, string firstName)
{
     return from u in users
            where u.FirstName == firstName
            select u;
}

Voici le code en mémoire qui fonctionne bien

var userlist = new List {new User{FirstName = "Test", LastName = "User"}};

Mapper.CreateMap();
var result = (from u in userlist
                   select Mapper.Map(u))
                   .AsQueryable()
                   .ByName("Test");

foreach (var x in result)
{
     Console.WriteLine(x.FirstName);
}

Voici la même chose en utilisant SubSonic (ou Linq to SQL ou autre) qui échoue. C'est ce que j'aimerais réussir à faire fonctionner d'une manière ou d'une autre avec des méthodes d'extension...

Mapper.CreateMap();

var result = from u in new DataClasses1DataContext().Users
                          select Mapper.Map(u);

var final = result.ByName("Test");
foreach(var x in final) // Échoue ici lorsque le graphe de requête est construit.
{
     Console.WriteLine(x.FirstName);
}

L'objectif ici est d'éviter d'avoir à mapper manuellement l'objet "User" généré avec l'objet de domaine "MyUser" - en d'autres termes, j'essaie de trouver un moyen d'utiliser AutoMapper pour ne pas avoir ce type de code de mappage partout où une opération de lecture en base de données est nécessaire :

var result = from u in new DataClasses1DataContext().Users
                          select new MyUser // Est-ce que cela peut être évité avec AutoMapper ET des méthodes d'extension ?  
                          {
                             FirstName = v.FirstName,
                             LastName = v.LastName
                          };

0voto

Gamlor Points 6823

Eh bien, je ne connais pas l'implémentation LINQ de SubSonic. Cependant, la cause du problème pourrait être que le fournisseur LINQ ne parvient pas à utiliser l'appel 'Mapper'. Il attend quelque chose qui peut être traduit en SQL.

Soit dit en passant, je utiliserais le .ByName() sur la requête 'User' au lieu de l'implémentation actuelle. Parce que actuellement, le résultat doit être mappé pour exécuter le .ByName(). Ainsi, vous récupérez beaucoup d'instances d'utilisateur de la base de données, les mappez et les filtrez ensuite. Si vous utilisiez .ByName sur l 'User', il pourrait être traduit en SQL et ne devrait jamais être récupéré.

Donc, je suppose que quelque chose comme cela fonctionnerait :

public static IQueryable ByName(this IQueryable utilisateurs, string prenom)
{
    return from u in utilisateurs
        where u.Prenom == prenom
        select u;
}

Et maintenant, vous ajoutez la partie mappage à la fin : Mapper.CreateMap();

var resultat = from u in new DataClasses1DataContext().Utilisateurs.ByName("Test")
                select Mapper.Map(u);
// maintenant la contrainte 'ByName' peut être exécutée sur la base de données

foreach(var x in resultat)
{
     Console.WriteLine(x.Prenom);
}

Si cela ne fonctionne toujours pas, vous devrez peut-être forcer l'utilisation de LINQ-to-Object pour la partie Mappage : Mapper.CreateMap();

var resultat = DataClasses1DataContext().Utilisateurs.ByName("Test").ToList();
// maintenant le resultat est une liste régulière, donc LINQ-to-object est utilisé pour la partie mappage

var final = from u in resultat
                   select Mapper.Map(u);

foreach(var x in final)
{
     Console.WriteLine(x.Prenom);
}

Soit dit en passant, vous voudrez peut-être ajouter une balise 'SubSonic', afin que les experts SubSonic répondent à votre question.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X