简体   繁体   中英

How can I upgrade to Automapper 9.0 for a query without using CreateMissingTypeMaps ( since is has been deprecated )?

I need to know how to upgrade AutoMapper from 8.0 to 9.0. All my queries generally look like the following. I query a subset of my data and create a DTO object to be sent to the client with minimal data. I don't use the entity framework with navigation properties or collections because the manageability and organization becomes hideous. Instead I use LINQ to join the data as needed with the smallest footprint possible simplifying the data access. Here is an example.

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

The query is simply a join on a the two sets of data to return a single classification for the the given company, employee, and classification.

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 Guidelines (these seem like common sense design principles)

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

I had to amend this post because I was working on an assumption that was not true. I believed that you could not select new POCO from an EntityFramework LINQ query without first bringing them into memory. This assumption was born through getting the following exception:

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.

My answer was to create an anonymous type and using AutoMapper's ProjectTo which handled the projection seamlessly. The part I didn't realize is that I missed the fact that POCOs are in fact compatible with LINQ queries using select new POCO

It appears that EF mapped types are not support and surely any classes that call or expose any .NET calls will also throw the System.NotSupportedException.

That said, while I have concerns about the usage of AutoMapper, there are viable use cases. I would just be cautious because the AM separates the definition of the type and the type itself and can easily get out of hand if not fully respected properly.

select new EmployeeClassificationModel
select new ClassificationCourseModel // for both lists

and the removal of the line ProjectTo() is the proper way to achieve the results I thought CreateMissingTypeMaps and the ProjectTo() were responsible for. I had to "take the L!" and accept that Lucian Bargaoanu had given the correct responses even though my assumptions had me believing the opposite.

Given the explanation of misdirection this is the solution to the problem of projecting the data to the dto objects.

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

The only differences in the DTO objects is that the collections were changed to IQueryable. At that point the SQL behind the query is available for inspection in the debugger the same as the anonymous object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM