Правилен начин за предаване на обекти на Entity между слоевете?

Току-що изучавам Entity Framework и постигнах добър напредък в включването му в моята структура на многослоен код. Имам 2 визуални слоя, бизнес слой и слой за достъп до данни.

Проблемът ми е в предаването на обект на обект между слоевете. Този примерен код не работи:

// 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;
 }
}

Получавам съобщение за грешка Екземплярът на ObjectContext е премахнат и вече не може да се използва за операции, които изискват връзка.

Ако премахна using от метода GetActiveUsers, той работи добре.

Знам, че това е опасна практика, тъй като GC може да се освободи от контекста във всеки един момент и да прецака моя BLL.

И така, какъв е правилният начин за предаване на информация между слоевете? Трябва ли да предавам и контекста?


person Scottie    schedule 04.11.2010    source източник


Отговори (1)


Тъй като връщате IQueryable от вашия DAL, не можете да използвате израза using.

Заявката е отложена до задействане на заявката - .ToList във вашия BLL.

По това време контекстът е изтрит.

Помислете внимателно относно използването на IQueryable, тъй като това е рискована практика без да знаете всички подробности.

Тъй като все още изучавате EF, бих го прост:

// 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();
 }
}

Ако искате да получите един потребител, създайте друг метод:

// 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();
 }
}
person RPM1984    schedule 05.11.2010
comment
Благодаря за предложението Ако обаче преобразувам своя обект в списък в DAL, не губя ли цялата функционалност, която получавам с EF? Например, ако искам да мога да правя страници в Silverlight, не бих искал непременно да заредя целия набор от данни в списък, нали? - person Scottie; 05.11.2010
comment
Нещо като. С IQueryable можете да „изграждате“ заявки по-късно (т.е. отложено изпълнение). Което ви дава много сила. Аз също използвам IQueryable. Но както казах, не можете да използвате израза „using“, когато използвате IQueryable. Трябва ръчно да отворите/затворите контекста от някъде другаде, силно препоръчвам IoC контейнер (като StructureMap) за това. В противен случай ще се окажете със стари връзки. - person RPM1984; 06.11.2010
comment
И не - вие наистина не губите функционалността, вие просто губите способността да имате груб контрол върху заявките извън DAL. Все още можете да правите страниране, просто създайте метод, който приема номер на страница и размер на страницата, след това страниците в действителния DAL метод и върнете списъка. Разгледайте някои от въпросите ми, които зададох, ако се интересувате от IQueryable, защото, както казах, в момента го използвам. Освен това оставянето на приложението Silverlight да изпълнява заявките е твърде късно. Трябва да отложите заявката само до BLL, не по-късно. В противен случай може да имате неочаквани резултати. - person RPM1984; 06.11.2010