Entity framework 自动映射嵌套映射和投影

Entity framework 自动映射嵌套映射和投影,entity-framework,automapper,Entity Framework,Automapper,关于博客数据模型,我有: public class Blog { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Post> Posts { get; set; } } public class Post { public int Id { get; set; } public string Text { get;

关于博客数据模型,我有:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Text { get; set; }
    public int BlogId { get; set; }

    public virtual Blog Blog { get; set; }
}
这是生成的表达式:

.Call System.Linq.Queryable.Select(
.Call 

.Constant<System.Data.Entity.Core.Objects.ObjectQuery`1[AutoMapperSample.Model.Post]>(System.Data.Entity.Core.Objects.ObjectQuery`1[AutoMapperSample.Model.Post]).MergeAs(.Constant<System.Data.Entity.Core.Objects.MergeOption>(AppendOnly))
    ,
    '(.Lambda #Lambda1<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>))

.Lambda #Lambda1<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>(AutoMapperSample.Model.Post $dto)
{
    .New AutoMapperSample.Model.PostDto(){
        Id = $dto.Id,
        Text = $dto.Text,
        Blog = .If ($dto.Blog != null) {
            .New AutoMapperSample.Model.BlogDto(){
                Id = ($dto.Blog).Id,
                Name = ($dto.Blog).Name,
                Posts = .Call System.Linq.Enumerable.ToList(.Call System.Linq.Enumerable.Select(
                        ($dto.Blog).Posts,
                        .Lambda #Lambda2<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>))
            }
        } .Else {
            null
        }
    }
}

.Lambda #Lambda2<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>(AutoMapperSample.Model.Post $dto)
{
    .New AutoMapperSample.Model.PostDto(){
        Id = $dto.Id,
        Text = $dto.Text
    }
}
.Call System.Linq.Queryable.Select(
呼叫
.Constant(System.Data.Entity.Core.Objects.ObjectQuery`1[AutoMapperSample.Model.Post]).mergas(.Constant(仅附录))
,
“(.Lambda#Lambda1))
.Lambda#Lambda1(AutoMapperSample.Model.Post$dto)
{
.New AutoMapperSample.Model.PostDto(){
Id=$dto.Id,
Text=$dto.Text,
Blog=.If($dto.Blog!=null){
.New AutoMapperSample.Model.BlogDto(){
Id=($dto.Blog).Id,
Name=($dto.Blog).Name,
Posts=.Call System.Linq.Enumerable.ToList(.Call System.Linq.Enumerable.Select)(
($dto.Blog),
.Lambda#Lambda(2))
}
}.其他{
无效的
}
}
}
.Lambda#Lambda2(AutoMapperSample.Model.Post$dto)
{
.New AutoMapperSample.Model.PostDto(){
Id=$dto.Id,
Text=$dto.Text
}
}

我需要知道结构是否有问题,比如循环,或者需要考虑其他问题

EF 6的预测有两个问题

1-不能将项目集设置为客户本身

比如说

公共类客户
{
公共int Id{get;set;}
公共字符串名称{get;set;}
[未映射]
公共int-ordersont{get;set;}
公共列表顺序{get;set;}
}
List customers=wait DbContext.customers.Select(cust=>
新客户
{
Id=客户Id,
Name=客户名称,
ordersont=cust.Orders.Count
}).ToListSync();//错误!
2-你不能同时投射关系的两面


public class Customer // as like as previous example

public class Order
{
     public int Id {get;set;}
     public int CustomerId {get;set;}
     public Customer Customer {get;set;}
}

List<CustomerDto> customers = await DbContext.Customers.Select(cust => 
     new CustomerDto
     {
          Id = cust.Id,
          Name = cust.Name,
          OrdersCount = cust.Orders.Count,
          Orders = cust.Orders.Select(ord => new OrderDto {
               Id = ord.Id,
               CustomerId = ord.CustomerId,
               Customer = new CustomerDto { ... }
          }).ToList()
     }).ToListAsync(); // error!


公共类Customer//与前面的示例相同
公共阶级秩序
{
公共int Id{get;set;}
public int CustomerId{get;set;}
公共客户客户{get;set;}
}
List customers=wait DbContext.customers.Select(cust=>
新顾客
{
Id=客户Id,
Name=客户名称,
ordersont=cust.Orders.Count,
订单=客户订单。选择(ord=>neworderdto{
Id=ord.Id,
CustomerId=ord.CustomerId,
Customer=新CustomerDto{…}
})托利斯先生()
}).ToListSync();//错误!
第一个问题是无法解决的,但对于第二个问题,您可以编写一个解决方案,忽略关联的一方(例如,在客户查询中返回带有订单的客户,但在订单查询中不返回客户!)

bool映射perpropConfigurationCondition(PropertyMap)
{
返回(p.DestinationMember.GetCustomAttribute()!=null | | p.DestinationMember.GetCustomAttribute()!=null)
&&!typeof(IEnumerable).IsAssignableFrom(p.DestinationMember.ReflectedType)
&&typeof(IDto).IsAssignableFrom(p.DestinationMember.ReflectedType);
}
mapperConfigExpression.ForAllPropertyMaps(MapperPropConfigurationCondition,(p,成员)=>
{
p、 忽略=真;
});

最终解决方案:迁移到EF Core 5,它拥有您所需的一切,您可以随时使用;D

Hm可能无法解析
PostDto.Blog
BlogDto.Posts
之间的循环引用。如果您
.Ignore()
CreateMap
中的其中一个成员,它是否工作?@GeorgPatscheider是的,如果我在BlogDto.Posts上放置IgnoreMap属性,或者如果我使用MaxDepth(1),它工作。但我认为应该有一个适当的方法来保持这两个导航属性。另外,我尝试了PreserveReferences方法,再次遇到相同的错误。
List<PostDto> result = null;
using (var db = new BloggingContext())
{
    result = db.Set<Post>().ProjectToList<PostDto>();
}
The type 'AutoMapperSample.Model.PostDto' appears in two structurally
incompatible initializations within a single LINQ to Entities query. A type
can be initialized in two places in the same query, but only if the same
properties are set in both places and those properties are set in the same
order.
.Call System.Linq.Queryable.Select(
.Call 

.Constant<System.Data.Entity.Core.Objects.ObjectQuery`1[AutoMapperSample.Model.Post]>(System.Data.Entity.Core.Objects.ObjectQuery`1[AutoMapperSample.Model.Post]).MergeAs(.Constant<System.Data.Entity.Core.Objects.MergeOption>(AppendOnly))
    ,
    '(.Lambda #Lambda1<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>))

.Lambda #Lambda1<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>(AutoMapperSample.Model.Post $dto)
{
    .New AutoMapperSample.Model.PostDto(){
        Id = $dto.Id,
        Text = $dto.Text,
        Blog = .If ($dto.Blog != null) {
            .New AutoMapperSample.Model.BlogDto(){
                Id = ($dto.Blog).Id,
                Name = ($dto.Blog).Name,
                Posts = .Call System.Linq.Enumerable.ToList(.Call System.Linq.Enumerable.Select(
                        ($dto.Blog).Posts,
                        .Lambda #Lambda2<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>))
            }
        } .Else {
            null
        }
    }
}

.Lambda #Lambda2<System.Func`2[AutoMapperSample.Model.Post,AutoMapperSample.Model.PostDto]>(AutoMapperSample.Model.Post $dto)
{
    .New AutoMapperSample.Model.PostDto(){
        Id = $dto.Id,
        Text = $dto.Text
    }
}

public class Customer // as like as previous example

public class Order
{
     public int Id {get;set;}
     public int CustomerId {get;set;}
     public Customer Customer {get;set;}
}

List<CustomerDto> customers = await DbContext.Customers.Select(cust => 
     new CustomerDto
     {
          Id = cust.Id,
          Name = cust.Name,
          OrdersCount = cust.Orders.Count,
          Orders = cust.Orders.Select(ord => new OrderDto {
               Id = ord.Id,
               CustomerId = ord.CustomerId,
               Customer = new CustomerDto { ... }
          }).ToList()
     }).ToListAsync(); // error!

bool MapperPropConfigurationCondition(PropertyMap p)
            {
                return (p.DestinationMember.GetCustomAttribute<ForeignKeyAttribute>() != null || p.DestinationMember.GetCustomAttribute<InversePropertyAttribute>() != null)
                       && !typeof(IEnumerable).IsAssignableFrom(p.DestinationMember.ReflectedType)
                       && typeof(IDto).IsAssignableFrom(p.DestinationMember.ReflectedType);
            }

            mapperConfigExpression.ForAllPropertyMaps(MapperPropConfigurationCondition, (p, member) =>
            {
                p.Ignored = true;
            });