Проекция данных в Entity Framework и Automapper - PullRequest
5 голосов
/ 22 марта 2011

Я хочу использовать AutoMapper для создания ViewModel (выравнивание - проекция данных) для использования в приложении ASP.net MVC.

var tmp = from x in db.Mailings select Mapper.Map<Mailing, MailingViewModel>(x);
return View(tmp.ToList());

Конечно, когда я пробую приведенный выше пример, я получаю ошибку EF «LINQ to Entities не распознает метод method ..., и этот метод не может быть преобразован в выражение хранилища».

Я знаю, что можно переместить .ToList () до того, как Automapper сделает свое волшебство, но затем я извлекаю все поля из БД (и мне нужно только 3 из 20 полей)

Можно ли использовать это чистым способом? Очистить = Не все поля выбираются из БД, но только поля, необходимые для ViewModel. Возможно ли это в Automapper? Или, может быть, другая библиотека? (не делая это вручную;))

Ответы [ 6 ]

9 голосов
/ 17 июля 2012

Да, это очень возможно.См. Здесь http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code

Редактировать: я недавно обнаружил, что основание для этого уже существует в AutoMapper.добавьте оператор использования для AutoMapper.QueryableExtensions, и вы получите расширение IQueryable с именем Project <> ()

4 голосов
/ 22 марта 2011

Вы можете просто позвонить:

var tmp = from x in db.Mailings 
          select new MailingViewModel
            {
               FirstName = x.FirstName,
               LastName = x.LastName,
               Address = x.Address
            };

Вам не нужен AutoMapper для простого проецирования, если вы обращаетесь к EF непосредственно в контроллере.

Вы не можете задействовать AutoMapper в запросе linq-to-entity - никак. Вы должны либо вернуть объект (или другой проектируемый объект) и отобразить его с помощью AutoMapper, либо использовать обычную проекцию без AutoMapper.

2 голосов
/ 22 марта 2011

Вы должны быть в состоянии сделать это, используя AutoMapper's DynamicMap .Я полагаю, что что-то вроде следующего порога решит вашу проблему, если вы действительно хотите использовать AutoMapper, хотя в этом конкретном случае я согласен с Ладиславом Мрнкой.

var tmp = from x in db.Mailings 
          select new
          {
              FirstName = x.FirstName,
              LastName = x.LastName,
              Address = x.Address
          };

return View(tmp.ToList().Select(item => Mapper.Map<MailingViewModel>(item)));

К сожалению, если вы хотите ограничить столбцы, вывозвращаясь из базы данных, вам нужно указать, какие из них вы хотите, что в данном сценарии не соответствует цели AutoMapper.Это было бы действительно аккуратное расширение AutoMapper, чтобы взять тип назначения и динамически создать выражение выбора, основанное на свойствах типа.

2 голосов
/ 22 марта 2011

Это вызвано тем, как linq взаимодействует с IQueryableProviders (я думаю, что это интерфейс).

Итак, происходит то, что Linq компилируется в дерево выражений, которое базовый поставщик linq читает и пытаетсяконвертировать в sql.Провайдер linq не знает, как перевести Mapper.Map<> в SQL, поэтому возникает ошибка.

Для хорошего видео о том, как работают провайдеры linq, посмотрите: http://channel9.msdn.com/Shows/Going+Deep/Erik-Meijer-and-Bart-De-Smet-LINQ-to-Anything

1 голос
/ 20 февраля 2015

, поскольку Automapper не работает непосредственно с базой данных (необходимо преобразовать его в объект в памяти, прежде чем обращаться к нему), я написал собственный простой класс для копирования идентичных свойств:

Исходный код:

  model.Sales = _dbcontext.Sales.Where(o => o.PartnerId == PartnerId && (o.SaleDate > model.BeginDate || model.BeginDate == null) && (o.SaleDate <= model.EndDate || model.EndDate == null)).Select(o => new SaleViewModel
        {
            NumberIn1S = o.NumberIn1S,
            Total = o.Total,
            SaleDate = o.SaleDate,
            Comments = o.Comments,
            Driver = o.Driver,
            GuidIn1S = o.GuidIn1S
        }).OrderByDescending(o => o.SaleDate).ToList(); </p>

MyMapper:

model.Sales = _dbcontext.Sales.Where(o => o.PartnerId == PartnerId && (o.SaleDate > model.BeginDate || model.BeginDate == null) && (o.SaleDate <= model.EndDate || model.EndDate == null)).OrderByDescending(o => o.SaleDate).ToArray().Select(p => <b>MyMapper<SaleViewModel>.CopyObjProperties(p, "NumberIn1S,Total,SaleDate,Comments,Driver,GuidIn1S")</b>).ToList(); </p>
1 голос
/ 15 марта 2013

Это можно сделать с помощью библиотеки LINQ Projector .Он основан на http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code и добавляет некоторые правила сопоставления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...