2010-09-21 4 views
6

J'ai un tas de méthodes Linq to Entity qui avaient la même instruction select, donc je pensais que je serais intelligent et séparer cela dans sa propre méthode pour réduire la redondance ... mais quand j'ai essayé d'exécuter le code, j'ai eu l'erreur suivante ...Quelles sont les causes de l'erreur Linq: Cette méthode ne peut pas être traduite en une expression de magasin?

this method cannot be translated into a store expression

Voici la méthode que je crée ...

public User GetUser(DbUser user, long uid) 
{ 
    return new User 
    { 
     Uid = user.uid, 
     FirstName = user.first_name, 
     LastName = user.last_name 
    }; 
} 

Et vous appelle dans une méthode comme ça ...

public User GetUser(long uid) 
{ 
    using (var entities = new myEntities()) { 
     return 
      entities.DbUsers.Where(x => x.uid == uid && x.account_status == (short)AccountStatus.Active). 
       Select(x => GetUser(x, uid)).FirstOrDefault(); 
    } 
} 

MISE À JOUR: voici le code qui fonctionne en ligne

public User GetUser(long uid, long uid_user) 
     { 
      using (var entities = new myEntities()) 
      { 

       var q = from u in entities.DbUsers 
         where u.uid == uid_user 
         select new User 
         { 
          Uid = u.uid, 
          FirstName = u.first_name, 
          LastName = u.last_name, 
          BigPicUrl = u.pic_big, 
          Birthday = u.birthday, 
          SmallPicUrl = u.pic_small, 
          SquarePicUrl = u.pic_square, 
          Locale = u.locale.Trim(), 
          IsFavorite = u.FavoriteFriends1.Any(x => x.uid == uid), 
          FavoriteFriendCount = u.FavoriteFriends.Count, 
          LastWishlistUpdate = u.WishListItems.OrderByDescending(x => x.added).FirstOrDefault().added, 
          Sex = (UserSex)u.sex 
         }; 

       var user = q.FirstOrDefault(); 
       user.DaysUntilBirthday = user.Birthday.DaysUntilBirthday(); 
       return user; 
      } 
     } 

Répondre

0

Vous ne pouvez pas faire cela parce que la méthode getUser ne peut pas être converti en toute déclaration TSQL. si vous retournez votre DBUser d'abord, puis l'utiliser comme premier paramètre de la méthode GetUser vous obligez à exécuter et une fois que vous avez-vous DBUser vous pouvez passer à GetUser

Peut-être que vous pouvez essayer ceci:

public User GetUser(long uid) 
{ 
    using (var entities = new myEntities()) 
    { 
     return GetUser(
      entities.DbUsers 
       .Where(x => x.uid == uid && x.account_status == (short)AccountStatus.Active) 
       .FirstOrDefault(), 
      uid); 
    } 
} 

EDIT

Puisque vous dites qu'il échoue encore pourrait-il être beacuse de l'ENUM ??

public User GetUser(long uid) 
{ 
    using (var entities = new myEntities()) 
    { 
     short status = (short)AccountStatus.Active; 
     return GetUser(
      entities.DbUsers 
       .Where(x => x.uid == uid && x.account_status == status) 
       .FirstOrDefault(), 
      uid); 
    } 
} 
+0

J'ai essayé cette technique et elle échoue toujours –

+0

Pourquoi avez-vous DbUser et utilisateur quand même? Les entités d'EF ne sont-elles pas supposées être vos entités de domaine ??? Il semble que l'utilisateur est une version simplifiée de DbUser pourquoi ne pas opérer sur DBUsers? –

+0

Je devine que DbUser est le EF POCO et User est son objet métier personnalisé. Pourtant, je préfère mapper directement à mon POCO personnalisé. Laisse tomber l'homme du milieu. – RPM1984

9

L'erreur est sur place, vous ne pouvez pas traduire cela en une requête T-SQL (ou P-SQL).

Vous devez vous assurer que vous avez exécuté la requête avant d'essayer de l'hydrater dans un autre type.

Restez simple, utilisez une méthode d'extension. C'est ce qu'ils sont là pour ça.

public static User ToUserEntity(this DbUser user) 
{ 
    return new User 
    { 
     Uid = user.uid, 
     FirstName = user.first_name, 
     LastName = user.last_name 
    }; 
} 

Puis dans votre DAL:

public User GetUser(long uid) 
{ 
    User dbUser; 

    using (var entities = new myEntities()) 
    { 
     dbUser = entities.DbUsers 
        .Where(x => x.uid == uid && x.account_status == (short)AccountStatus.Active) 
       .FirstOrDefault(); // query executed against DB 
    } 

    return dbUser.ToUserEntity(); 
} 

Voyez comment je hydrate Poco dans un objet après le contexte a été disposé? De cette façon, vous vous assurez qu'EF a terminé son travail d'expression avant d'essayer de vous hydrater dans un objet personnalisé.

Aussi je ne sais pas pourquoi vous passez uid à cette méthode, il n'est même pas utilisé. Sur une note supplémentaire, vous ne devriez pas besoin de pour faire ce genre de chose (projet EF POCO dans vos propres objets).

Si vous le faites, c'est un bon cas pour les POCO personnalisés (mappez les tableaux directement dans vos POCO personnalisés, n'utilisez pas la génération de code).

+0

Eh bien, j'utilise l'uid dans un morceau de la requête qui ne s'affiche pas ici (cela n'a pas d'impact sur l'erreur). Quand j'ai eu cette déclaration en ligne, cela a très bien fonctionné. Mais quand je déplace le code dans sa propre méthode si échoue. Pourquoi le compilateur ne peut-il pas simplement impliquer que cette expression appartient à l'instruction EF? Je sais que je pourrais hydrater cet objet par la suite, mais j'ai plusieurs champs qui doivent fonctionner sur le contexte db. Ils sont simplement répétés inline (et ils ont bien fonctionné). Je ne comprends vraiment pas pourquoi vous ne pouvez pas extraire cette fonctionnalité dans sa propre méthode. –

+0

@wcpro - pouvez-vous montrer le code où il fonctionne en ligne? Je serais très intéressé de voir comment Entity Framework a réussi à "deviner" les relations entre l'utilisateur (un objet CLR aléatoire) et DbUser (un objet EF) afin de créer l'expression de la requête. – RPM1984

+0

Quoi qu'il en soit, avez-vous essayé ma réponse - il devrait fonctionner (sauf si vous avez un problème enum, comme le dit Carlos ci-dessous) – RPM1984

3

Cette expression fonctionnera pour donner le résultat souhaité (quelque peu) Je n'ai toujours pas compris comment passer des variables supplémentaires dans les instructions select ...

..... .Select(GetUser).FirstOrDefault()   

static readonly Expression<Func<DbUser, User>> GetUser = (g) => new User { 
      Uid = g.uid, 
      FirstName = g.first_name, 
      LastName = g.last_name, 
      BigPicUrl = g.pic_big, 
      Birthday = g.birthday, 
      SmallPicUrl = g.pic_small, 
      SquarePicUrl = g.pic_square, 
      Locale = g.locale.Trim(), 
      //IsFavorite = g.FavoriteFriends1.Any(x=>x.uid==uid), 
      FavoriteFriendCount = g.FavoriteFriends.Count, 
      LastWishlistUpdate = g.WishListItems.OrderByDescending(x=>x.added).FirstOrDefault().added 
     }; 
+0

J'aime vraiment cette cause, vous pouvez l'utiliser dans la requête linq avant qu'elle ne soit énumérée, donc cela fonctionne avec les listes. – tkerwood

Questions connexes