#c# #automapper
#c# #automapper
Вопрос:
У меня есть три класса:
public class UserReport : Entity
{
public string Name { get; set; }
public string Email { get; set; }
public List<string> Departments { get; set; }
public List<string> Titles { get; set; }
}
public abstract class Entity
{
public Guid Id { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateLastModified { get; set; }
public string CreatedBy { get; set; }
public string LastModifiedBy { get; set; }
public bool Active { get; set; }
protected Entity()
{
DateCreated = DateTime.Now;
DateLastModified = DateTime.Now;
Id = Guid.NewGuid();
}
}
public class UserModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Departments { get; set; }
public string Titles { get; set; }
}
С моими настройками automapper, установленными как:
CreateMap<List<string>, string>().ConvertUsing(strings => {
if (strings != null)
return string.Join("n", strings);
return "";
});
CreateMap<UserReport, UserModel>();
При попытке вызова из универсального метода с использованием расширений Automapper Ef:
IQueryable<TModel> modelQueryable = _reportService.GetReportBaseQuery().ProjectToQueryable<TModel>();
Я получаю эту ошибку
Отсутствует карта из системы.Строка в System.Char. Создайте с помощью Mapper.Создайте карту.
GetReportBaseQuery()
возвращает IQueryable<TReport>
, поэтому UserReport
в данном случае. Я не вижу никаких char
свойств, почему это происходит?
Просто для тестирования я попытался создать его:
CreateMap<String, Char>().ConvertUsing(x => x.FirstOrDefault());
И затем он говорит:
Типы аргументов не совпадают
Дальнейшие исследования показывают, что это работает:
Mapper.Map<List<TReport>, List<TModel>>(_reportService.GetReportBaseQuery().ToList());
Но я не могу использовать это, так как мне нужно, чтобы оно возвращалось с запросом. Итак, что-то меняется, когда я пытаюсь выполнить проекцию EF, хотя не уверен, что это такое. Написать оператор select от одного к другому достаточно просто, но это не универсально и не может быть использовано повторно.
Комментарии:
1. Можете ли вы попробовать это:
CreateMap<UserReport, UserModel>().ForMember(x => x.Departments, o => o.MapFrom(s => string.Join("n", s.Departments))).ForMember(x => x.Titles, o => o.MapFrom(s => string.Join("n", s.Titles)));
? У меня есть гипотеза, но я не уверен, правильно ли это2. Откуда
.ProjectToQueryable<TModel>()
берется? Я установил AutoMapper. EF6 Nuget, но не может его найти, и кажется, что это ключ к воспроизведению ошибки3. @JakubJankowski вы должны иметь возможность добавлять
using AutoMapper.QueryableExtensions;
, а затем вы должны увидеть расширениеProjectToQueryable
Кстати, я воссоздавал проблему и попробовал ваше предложение, и, похоже, оно исправляет отображение, мне интересно, обрабатывает ли Automapper каждую строку вList<string>
виде списка символов и ищет сопоставление для них4. Да, оглядываясь назад, я уже знал эту проблему:
LINQ to Entities does not recognize the method 'System.String Join(System.String, System.Collections.Generic.IEnumerable
1 [System. String])’метод, и этот метод не может быть преобразован в выражение хранилища. `5. Ну, я только что нашел метод и воспроизвел вашу ошибку. Действительно, расширения обрабатывают string как набор символов, а List<string> — как набор строк, таким образом пытаясь сопоставить:
string
=>char
. Должен ли я создать ответ из своих комментариев?
Ответ №1:
Решение состоит в том, чтобы явно установить сопоставление для полей Departments
и Titles
:
CreateMap<UserReport, UserModel>()
.ForMember(x => x.Departments, o => o.MapFrom(s => string.Join("n", s.Departments)))
.ForMember(x => x.Titles, o => o.MapFrom(s => string.Join("n", s.Titles)));
Но это не объясняет, почему возникает такая ситуация.
Как указал ДОТанг:
LINQ to Entities не распознает метод ‘System.Соединение строк (System.Строка, Система.Коллекции.Общий.IEnumerable1[System.Метод String])’, и этот метод не может быть преобразован в выражение хранилища.
Расширение AutoMapper, похоже, пытается отобразить следующую вещь:
IEnumerable<string> => IEnumerable<char>