LINQ to Entities - поддержка замыканий (Lambdas)? - PullRequest
1 голос
/ 02 февраля 2010

Я работал над проблемой, возникающей при использовании LINQ to Entities при использовании замыканий.

Очевидно, L2E не поддерживает замыкания. Значение:

var users = from user in UserRepository.FindAll()
            select new UserDTO
            {
               UserId = user.UserId,
               Tickets = from ticket in TicketRepository.FindAll()
                         where ticket.User == user
                         select new TicketDTO
                         {
                           TicketId = ticket.TicketId
                         }
            };

(ПРИМЕЧАНИЕ. Условие "где" - это проблема, в которой существует проблема. Мне не разрешено сравнивать сущность с другой сущностью, поскольку они не являются примитивными типами EF. Допускаются только такие вещи, как Int32, Guid и т. Д.) 1006 *

, недопустимо, потому что я не могу сравнить 'ticket.User' с 'user'

Это просто пример моей проблемы, и я понимаю, что могу сравнить по Id, поскольку это примитивный тип, а не замыкание.

На самом деле мой сценарий намного сложнее, чем этот, но это сценарий, который мне нужно решить на данный момент.

Обходной путь, который я нашел в Интернете, использует подзапрос. Это работает, но для моего сценария это не очень эффективно.

Вопрос:

Кто-нибудь из вас знает, если:

  1. Entity Framework 4 будет поддерживать замыкания в LINQ для сущностей?
  2. Есть лучшее решение этой проблемы, чем использование подзапросов?
  3. Будем весьма благодарны за любые дополнительные знания по этой теме!

Ответы [ 2 ]

2 голосов
/ 02 февраля 2010

Это не проблема, напрямую связанная с замыканиями. Проблема (вероятно) в том, что вы смешиваете сущности Entity Framework и ваши объекты передачи данных. Поставщик LINQ пытается преобразовать дерево выражений вашего запроса в операторы SQL и терпит неудачу, потому что он не может отделить объекты передачи данных от сущностей, а база данных, конечно же, не может работать и с объектами передачи данных.

Я предлагаю сделать разделение намного чище - сначала получить данные из базы данных, используя LINQ to Entity и, возможно, анонимные типы, если необходимо, затем переключиться на LINQ to Objects, чтобы создать объекты передачи данных из извлеченных данных, и все должно хорошо. Что-то вроде следующего. (Просто чтобы заметить - я (безопасно) предполагаю, что репозитории возвращают IQueryable<T> s (иначе весь материал не должен работать вообще).)

var result = UserRepository
      .FindAll()
      .Select(user => new
         {
            UserId    = user.UserId,
            TicketIds = TicketRepository
                           .FindAll()
                           .Where(ticket => ticket.User.UserId == user.UserId)
                           .Select(ticket => ticket.TicketId)
         });

Преобразование этого результата запроса в объекты передачи данных теперь просто. Обратите внимание, что пользователи сравниваются по идентификаторам, потому что Entity Framework (пока) не поддерживает сравнения по ссылке.

0 голосов
/ 02 февраля 2010

Проблема здесь в том, что L2E не поддерживает ссылочное равенство материализованных объектов и объектов в БД, поэтому вам нужно сравнить на основе PK:

var users = from user in UserRepository.FindAll()
            select new UserDTO
            {
               UserId = user.UserId,
               Tickets = from ticket in TicketRepository.FindAll()
                         where ticket.User.UserId == user.UserId
                         select new TicketDTO
                         {
                           TicketId = ticket.TicketId
                         }
            };

(Предполагается, что здесь PK User называется UserId.)

...