2010-05-25 5 views
9

J'ai le code quelque chose comme cela dans une mise en œuvre IRepository dans LINQ to Sql:utilisation délégué pour la projection dans LINQ to SQL

var newlist = from h in list where h.StringProp1 == "1" 
         select new MyBusinessBO{ 
          firstProp = h.StringProp1, 
          secondProp = h.StringProp2 
         }; 

La projection dans MyBusinessBO n'est pas difificult mais quand l'objet d'affaires possède de nombreuses propriétés de la projection le code devient très long. De plus, comme la projection peut se produire à plusieurs endroits dans le dépôt, nous brisons le principe DRY.

Existe-t-il un moyen d'extraire la projection ou de la remplacer par un délégué?

I.e. remplacer le code

      firstProp = h.StringProp1, 
          secondProp = h.StringProp2 

avec quelque chose de réutilisable?

Répondre

5

Queryable.Select nécessite un Expression<Func<T, U>>. Vous pouvez écrire une méthode qui renvoie ceci et utiliser cette méthode partout où vous faites la transformation.

public Expression<Func<DataObj, BusiObj>> GetExpr() 
{ 
    return h => new BusiObj() 
    { 
    firstProp = h.StringProp1, 
    secondProp = h.StringProp2 
    }; 
} 


//get a local variable holding the expression. 
Expression<Func<DataObj, BusiObj>> toBusiObj = GetExpr(); 

//use it thusly 
var newList = (from h in list where h.StringProp1 == "1" select h) 
    .Select(toBusiObj) 
    .ToList(); 

//or 
List<BusiObj> newList = list 
    .Where(h => h.StringProp1 == "1") 
    .Select(toBusiObj) 
    .ToList(); 
+0

Une approche très similaire à ckknight ci-dessus, mais il semble que ce soit meilleur pour créer un code plus clair. Il a la projection dans une fonction réutilisable séparée qui peut simplement être transmise. ckknight a eu la réponse mais David B, vous avez travaillé de manière à ce que je sois où je veux être. J'ai répondu à ckknight et accepté celui-ci. – Redeemed1

+0

Soyez averti: Il est extrêmement important d'utiliser la syntaxe exacte indiquée ici pour la fonction 'GetExpr()'. Si vous avez une méthode de conversion DTE préexistante que vous avez utilisée à plusieurs endroits comme 'public DTE Convert (entité entité)' que vous essayez de convertir en une expression réutilisable, vous devez supprimer le paramètre 'entity' et créer le lambda comme indiqué ici - sinon, CHAQUE colonne de cette table sera récupérée. –

0

Jetez un oeil à AutoMapper et des outils similaires

+0

oui, en fait déjà en utilisant automapper largement, dans ce cas ce n'était pas la meilleure approche – Redeemed1

0

Peut-être utiliser les constructeurs non-défaut réguliers, plutôt que initialiseurs d'objets. Ou, si vous pouvez commencer à utiliser C# 4.0, essayez d'ajouter des paramètres optionnels/par défaut au mélange.

7

Vous pouvez résoudre ce problème en utilisant la syntaxe point plutôt que la syntaxe de style LINQ.

Votre actuelle:

list 
    .Where(h => h.StringProp1 == "1") 
    .Select(h => new MyBusinessBO 
    { 
     firstProp = h.StringProp1, 
     secondProp = h.StringProp2 
    }); 

solution potentielle:

Func<MyType, MyBusinessBO> selector = h => new MyBusinessBO 
{ 
    firstProp = h.StringProp1, 
    secondProp = h.StringProp2 
}; 
list 
    .Where(h => h.StringProp1 == "1") 
    .Select(selector); 

Et vous pouvez passer dans le sélecteur quelque part ou de générer sur la volée ou quelque chose le long de ces lignes.

+0

Belle réponse. J'irais même plus loin et je définirais ce 'Func' comme une vraie méthode. L'OP veut réutiliser cette logique de projection. – Steven

+0

Tu m'as battu dessus. +1 –

+0

Une considération avant d'utiliser cette réponse est que 'Func ' ne peut pas être projeté en SQL avec Entity Framework. Je me rends compte que la question cible 'Linq-to-SQL' qui peut être capable de faire la projection, mais pour écrire du code plus résistant au temps, rendre votre variable' Expression > 'pourrait être mieux. – ErikE