.net 如何对单个(非集合)图元使用投影表达式?

f45qwnt8  于 2022-11-26  发布在  .NET
关注(0)|答案(1)|浏览(107)

使用.net-6和EF Core 6,我希望使用表达式定义可重用的投影,以便可以将DTOMap集中在一个位置。
给定具有关系的实体:

class Property {
  public int Id {get; set;}
  public List<Amenity> Amenities {get; set;}
  public Address Address {get; set;}
}

class Amenity {
  public int Id {get; set;}
  public string Name {get; set;}
  public string Value {get; set;}
}

class Address {
  public int Id {get; set;}
  public string Country {get; set;}
  public string City {get; set;}
  public string Street {get; set;}
}

他们的DTO:

class PropertyDto {
  public int Id {get; set;}
  public List<AmenityDto> Amenities {get; set;}
  public AddressDto Address {get; set;}
}

class AmenityDto{
  public int Id {get; set;}
  public string Name {get; set;}
  public string Value {get; set;}
}

class AddressDto{
  public int Id {get; set;}
  public string Country {get; set;}
  public string City {get; set;}
  public string Street {get; set;}
}

我可以创建一个可重用的投影表达式:

public class PropertyDto {
  ...
  public static Expression<Func<Property, PropertyDto>> Projection =
    property => new PropertyDto{
      Id = property.Id,
    };
  ...
}

我可以在任何查询的Select()调用中使用它作为投影表达式,EF将“访问”它并将其转换为SQL,以便只获取我需要的那些列:

DbContext.Set<Property>()
  .Select(Property.Projection)
  .ToListAsync();

如果我想重用Amenities的投影,我可以为AmenityDto创建一个投影表达式,并执行以下操作:

public static Expression<Func<Property, PropertyDto>> Projection =
    property => new PropertyDto{
      Id = property.Id,
      Amenities = property.Amenities.AsQueryable().Select(Amenity.Dto).ToList(),
    };

但是如果我想对Address做同样的事情,我不能用.Select()来投影它,因为它不是一个集合。

public static Expression<Func<Property, PropertyDto>> Projection =
    property => new PropertyDto{
      Id = property.Id,
      Amenities = property.Amenities.AsQueryable().Select(Amenity.Dto).ToList(),
      Address = // how can I use AddressDto.Projection here?
    };

地址字段需要一个AddressDto。如果我使用回调,例如AddressDto.Projection(address) EF将加载整个实体,因为它不能将方法转换为SQL。在搜索了很多次之后,我只看到一些文章讨论使用.AsExpandable()[ReplaceWithExpression]属性来指示EF用表达式替换方法。据我所知,EF Core 6.0不再支持这些功能
在投影单个实体时,是否有任何方法可以重用投影表达式?

j2cgzkjk

j2cgzkjk1#

只是为了回答我自己的问题,并感谢@SvyatoslavDanyliv的评论,以下是我所做的来解决我的问题:
1.我安装了LinqKit.Microsoft.EntityFrameworkCore
1.我创建了一个方法,该方法返回用于将领域模型投影到Dto等价物的表达式:

public static Expression<Func<Address, AddressDto>> Projection() =>
   address => new AddressDto
   {
       Id = address .Id,
       Country = address.Country,
       City = address.City,
       Street = address.Street,
   };

1.我创建了将从其他投影中调用的方法,LinqKit将用上面的投影表达式替换该方法。

[Expandable(nameof(Projection))]
public static AddressDto FromEntity(Address address)
{
    // If you want to use this method outside of projections
    // return Projection().Compile().Invoke(address);
    throw new NotImplementedException();
}

我决定使用throw new NotImplementedException(),因为我只会从投影中调用此方法,但是如果您希望重用此方法在代码库中的其他位置创建DTO,则可以编译和调用投影。
1.我在我的父EF投影中使用了可替换的Dto投影方法:

...
.Select(property => new PropertyDto{
   Id = property.Id,
   Address = AddressDto.FromEntity(property.Address),
   ...
})
...

生成的EF SQL仅正确选择子Dto使用的那些列。

相关问题