mic*_*ael 4 c# entity-framework expression-trees entity-framework-core
使用 Entity Framework Core 进行查询时,我使用表达式转换为 DTO 对象,这对于对象和任何子集合都很有效。
一个简化的例子:
模型:
public class Model
{
public int ModelId { get; set; }
public string ModelName { get; set; }
public virtual ICollection<ChildModel> ChildModels { get; set; }
// Other properties, collections, etc.
public static Expression<Func<Model, ModelDto>> AsDto =>
model => new ModelDto
{
ModelId = model.ModelId,
ModelName = model.ModelName,
ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList()
};
}
Run Code Online (Sandbox Code Playgroud)
询问:
dbContext.Models.Where(m => SomeCriteria).Select(Model.AsDto).ToList();
Run Code Online (Sandbox Code Playgroud)
我的问题是试图找到一种方法为非集合的孩子做类似的事情。如果我已添加到我的模型中:
public AnotherChildModel AnotherChildModel { get; set; }
Run Code Online (Sandbox Code Playgroud)
我可以在表达式中添加转换:
public static Expression<Func<Model, ModelDto>> AsDto =>
model => new ModelDto
{
ModelId = model.ModelId,
ModelName = model.ModelName,
ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(),
AnotherChildModel = new AnotherChildModelDto
{
AnotherChildModelId = model.AnotherChildModelId
}
};
Run Code Online (Sandbox Code Playgroud)
但是,我还没有找到一种好方法来避免每次需要将第二个子模型转换为 DTO 对象时重复此代码。这些表达式适用于主对象和任何子集合,但不适用于单个实体。有没有办法为单个实体添加 .Select() 的等效项?
有几个库可以以直观的方式做到这一点:
[Expandable(nameof(AsDtoImpl))]
public static ModelDto AsDto(Model model)
{
_asDtoImpl ??= AsDtoImpl() .Compile();
return _asDtoImpl(model);
}
private static Func<Model, ModelDto> _asDtoImpl;
private static Expression<Func<Model, ModelDto>> AsDtoImpl =>
model => new ModelDto
{
ModelId = model.ModelId,
ModelName = model.ModelName,
ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(),
AnotherChildModel = new AnotherChildModelDto
{
AnotherChildModelId = model.AnotherChildModelId
}
};
Run Code Online (Sandbox Code Playgroud)
dbContext.Models
.Where(m => SomeCriteria).Select(m => Model.AsDto(m))
.AsExpandable()
.ToList();
Run Code Online (Sandbox Code Playgroud)
更新:对于 EF Core,LINQKit 可以全局配置并且AsExpanding()可以省略。
dbContext.Models
.Where(m => SomeCriteria).Select(m => Model.AsDto(m))
.AsExpandable()
.ToList();
Run Code Online (Sandbox Code Playgroud)
NeinLinq - 几乎与 LINQKit 中的相同
builder
.UseSqlServer(connectionString)
.WithExpressionExpanding(); // enabling LINQKit extension
Run Code Online (Sandbox Code Playgroud)
dbContext.Models
.Where(m => SomeCriteria).Select(m => Model.AsDto(m))
.ToInjectable()
.ToList();
Run Code Online (Sandbox Code Playgroud)
更新:对于 EF Core,NenLinq 可以全局配置并且ToInjectable()可以省略。
[InjectLambda]
public static ModelDto AsDto(Model model)
{
_asDto ??= AsDto() .Compile();
return _asDto(model);
}
private static Func<Model, ModelDto> _asDto;
private static Expression<Func<Model, ModelDto>> AsDto =>
model => new ModelDto
{
ModelId = model.ModelId,
ModelName = model.ModelName,
ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(),
AnotherChildModel = new AnotherChildModelDto
{
AnotherChildModelId = model.AnotherChildModelId
}
};
Run Code Online (Sandbox Code Playgroud)
DelegateDecompiler - 比其他的更简洁
dbContext.Models
.Where(m => SomeCriteria).Select(m => Model.AsDto(m))
.ToInjectable()
.ToList();
Run Code Online (Sandbox Code Playgroud)
dbContext.Models
.Where(m => SomeCriteria).Select(m => Model.AsDto(m))
.Decompile()
.ToList();
Run Code Online (Sandbox Code Playgroud)
所有库都执行相同的操作 - 在 EF Core 处理之前纠正表达式树。它们都需要额外的调用来注入它自己的IQueryProvider。
| 归档时间: |
|
| 查看次数: |
1978 次 |
| 最近记录: |