2010-11-04 37 views
3

Je viens d'apprendre l'Entity Framework et j'ai fait de bons progrès pour l'intégrer à ma structure de code en couches. J'ai 2 couches visuelles, une couche de gestion et une couche d'accès aux données.Manière correcte de passer des objets Entity entre les calques?

Mon problème est de passer l'objet entité entre les couches. Cet exemple de code ne fonctionne pas:

// BLL 
public static void Test1() 
{ 
List<User> users = (from u in GetActiveUsers() 
     where u.ID == 1 
     select u).ToList<User>(); 

// Do something with users 
} 

// DAL 
public static IQueryable<User> GetActiveUsers() 
{ 
using (var context = new CSEntities()) 
{ 
    return from u in context.Users 
     where u.Employee.FirstName == "Tom" 
     select u; 
} 
} 

Je reçois le message d'erreur L'instance ObjectContext a été disposé et ne peut plus être utilisé pour les opérations qui nécessitent une connexion.

Si je supprime le en utilisant de la méthode GetActiveUsers, cela fonctionne correctement.

Je sais que c'est une pratique dangereuse car le GC peut se débarrasser du contexte à tout moment et bousiller mon BLL.

Alors, quelle est la bonne façon de transmettre des informations entre les couches? Dois-je aussi faire circuler le contexte?

Répondre

5

Parce que vous retournez IQueryable de votre DAL, vous ne pouvez pas utiliser le using.

La requête est reportée jusqu'à à la requête de cuisson sont - .ToList dans votre BLL.

A ce moment-là, le contexte est éliminé.

Pensez soigneusement sur l'utilisation de IQueryable, car il est risqué de pratiquer sans connaître tous les détails.

Puisque vous apprenez toujours EF, je garderais simple:

// BLL 
public static void Test1() 
{ 
List<User> users = GetActiveUsers(); 
var singleUser = users.SingleOrDefault(u => u.ID == 1); 

// Do something with users 
} 

// DAL 
public static ICollection<User> GetActiveUsers() 
{ 
using (var context = new CSEntities()) 
{ 
    var users = from u in context.Users 
     where u.Employee.FirstName == "Tom" 
     select u; 
    return users.ToList(); 
} 
} 

Si vous souhaitez obtenir un seul utilisateur, créez une autre méthode:

// DAL 
public static User GetSingleActiveUser(int userId) 
{ 
using (var context = new CSEntities()) 
{ 
    var users = from u in context.Users 
     where u.Employee.UserId == userId 
     select u; 
    return users.SingleOrDefault(); 
} 
} 
+0

Merci pour la suggestion. Cependant, si je convertis mon entité en une liste dans le DAL, est-ce que je ne perds pas toutes les fonctionnalités que je reçois avec EF? Par exemple, si je veux pouvoir mettre en page dans Silverlight, je ne voudrais pas forcément charger l'intégralité du jeu de données dans une liste, n'est-ce pas? – Scottie

+0

Trier par. Avec IQueryable, vous pouvez «construire» des requêtes plus tard (c'est-à-dire une exécution différée). Ce qui vous donne beaucoup de pouvoir. J'utilise aussi IQueryable. Mais comme je l'ai dit, vous ne pouvez pas utiliser l'instruction 'using' lorsque vous utilisez IQueryable. Vous devez ouvrir/fermer manuellement le contexte depuis un autre endroit, je recommande fortement un conteneur IoC (comme StructureMap) pour cela. Sinon, vous finirez avec les anciennes connexions qui traînent. – RPM1984

+0

Et non - vous ne perdez pas vraiment la fonctionnalité, vous perdez simplement la possibilité d'avoir un contrôle grossier sur les requêtes en dehors de la DAL. Vous pouvez toujours faire de la pagination, il suffit de créer une méthode qui accepte un numéro de page et une taille de page, puis une page dans la méthode DAL réelle et de retourner la liste. Jetez un oeil à certaines de mes questions que j'ai demandé si vous êtes intéressé par IQueryable, parce que comme je l'ai dit je l'utilise actuellement. De même, laisser l'application Silverlight exécuter les requêtes est trop tardive. Vous devriez seulement reporter la requête à la BLL, pas plus tard. Sinon, vous pourriez avoir des résultats inattendus. – RPM1984