Как я могу обновить до Automapper 9.0 для запроса без использования CreateMissingTypeMaps (так как это устарело)? - PullRequest
0 голосов
/ 29 февраля 2020

Мне нужно знать, как обновить AutoMapper с 8.0 до 9.0. Все мои запросы обычно выглядят следующим образом. Я запрашиваю подмножество своих данных и создаю объект DTO для отправки клиенту с минимальными данными. Я не использую структуру сущностей со свойствами навигации или коллекциями, потому что управляемость и организация становятся отвратительными. Вместо этого я использую LINQ для объединения данных по мере необходимости с минимальной занимаемой площадью, что упрощает доступ к данным. Вот пример.

public class ClassificationCourseModel {
    public DateTime? PassedDate { get; set; }
    public String Title { get; set; }
    public String Status { get; set; }
}

public class EmployeeClassificationModel
{
    [Key] public int Id { get; set; }
    public string Description { get; set; }
    public Boolean HasCourses { get; set; }
    public Boolean IsCurrent { get; set; }
    public List<ClassificationCourseModel> CompleteCourses { get; set; }
    public List<ClassificationCourseModel> IncompleteCourses { get; set; }
}

Запрос - это просто объединение двух наборов данных, чтобы получить единую классификацию для данной компании, сотрудника и классификации.

var courseData =
    from crs in _database.ClassificationCourses
    where crs.EmployeeId == employeeId
    where crs.CompanyId == companyId
    where crs.Id == siteEntry.CompanyClassificationId
    select crs;

var classificationData = (
    from r in _database.EmployeeClassifications
    where r.EmployeeId == employeeId
    where r.CompanyId == companyId
    where r.CompanyClassificationId == siteEntry.CompanyClassificationId
    let courses = courseData.Where(c => c.Id == r.CompanyClassificationId)
    select new
    {
        r.Id,
        r.Description,
        r.IsCurrent,
        HasCourses = courseData.Any(),
        CompleteCourses = from crs in courses where crs.Completed select crs,
        IncompleteCourses = from crs in courses where !crs.Completed select crs
    }
).ProjectTo<EmployeeClassificationModel>(_mapper.ConfigurationProvider);

Правила AutoMapper (это похоже на принципы проектирования здравого смысла)

  1. https://jimmybogard.com/automapper-usage-guidelines/

Мне пришлось изменить этот пост, потому что я работал над предположением, которое не соответствует действительности. Я считал, что вы не можете выбрать новый POCO из запроса EntityFramework LINQ без предварительного переноса их в память. Это предположение родилось благодаря получению следующего исключения:

An exception of type 'System.NotSupportedException' occurred in 
EntityFramework.SqlServer.dll but was not handled in user code.

Additional information: The entity or complex type 'xxx' cannot be constructed 
in a LINQ to Entities query.

Мой ответ состоял в том, чтобы создать анонимный тип и использовать ProjectTo от AutoMapper, который без проблем обрабатывал проекцию. Часть, которую я не осознавал, это то, что я упустил тот факт, что POCO фактически совместимы с LINQ-запросами, используя select new POCO

. Кажется, что сопоставленные типы EF не поддерживаются и, безусловно, классы, которые вызывают или предоставляют любые вызовы. NET, также будут вызывать исключение System.NotSupportedException.

Тем не менее, хотя у меня есть опасения по поводу использования AutoMapper, существуют жизнеспособные варианты использования. Я просто был бы осторожен, потому что AM разделяет определение типа и самого типа и может легко выйти из-под контроля, если не будет должным образом соблюдаться.

select new EmployeeClassificationModel
select new ClassificationCourseModel // for both lists

и удаление строки ProjectTo () является правильным способом достижения результатов, за которые, как я думал, отвечают CreateMissingTypeMaps и ProjectTo (). Я должен был "взять L!" и признать, что Люциан Баргаоану дал правильные ответы, хотя мои предположения заставили меня поверить в обратное.

1 Ответ

0 голосов
/ 02 марта 2020

Учитывая объяснение неправильного направления, это решение проблемы проецирования данных на объекты dto.

var courseData = 
    from crs in _database.ClassificationCourses
    where crs.EmployeeId == employeeId
    where crs.CompanyId == companyId
    where crs.Id == siteEntry.CompanyClassificationId
    select crs;

var classification = 
    from r in _database.EmployeeClassifications
    where r.EmployeeId == employeeId
    where r.CompanyId == companyId
    where r.CompanyClassificationId == siteEntry.CompanyClassificationId
    let courses = courseData.Where(c => c.Id == r.CompanyClassificationId)
    select new EmployeeClassificationModel
    {
       Id = r.Id,
       Description = r.Description,
       IsCurrent = r.IsCurrent,
       HasCourses = courseData.Any(),
       CompleteCourses = 
                    from crs in courses
                    where crs.Completed
                    select new ClassificationCourseModel
                    {
                        Title = crs.Title,
                        PassedDate = crs.PassedDate,
                        Status = crs.Status
                    },
       IncompleteCourses = 
                from crs in courses
                where !crs.Completed
                select new ClassificationCourseModel
                {
                    Title = crs.Title,
                    PassedDate = crs.PassedDate,
                    Status = crs.Status
                }
    };

Единственным отличием в объектах DTO является то, что коллекции были изменены на IQueryable. На этом этапе SQL, стоящий за запросом, доступен для проверки в отладчике так же, как и анонимный объект.

...