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() }; }
和查询:
dbContext.Models.Where(m => SomeCriteria).Select(Model.AsDto).ToList();
但是,问题出现了:如何才能类似对于不是集合的子实体可以实现行为吗?例如,如果 Model 类包含属性:
public AnotherChildModel AnotherChildModel { get; set; }
可以将转换添加到表达式:
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 } };
但是每次第二个子模型需要时都重复此代码转换为 DTO 对象是不可取的。对于单个实体,是否有使用 .Select() 的替代方法?
几个库为这个问题提供了直观的解决方案:
1. LINQKit:
使用 LINQKit,.Select() 操作可以使用 ExpandableAttribute 应用于各个实体:
[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 } };
查询可以写为:
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .AsExpandable() .ToList();
2。 NeinLinq:
与 LINQKit 类似,NeinLinq 使用 InjectLambda 属性:
[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 } };
查询可以修改如下:
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .ToInjectable() .ToList();
3. DelegateDecompiler:
DelegateDecompiler 使用 Computed 属性提供了一种简洁的方法:
[Computed] public static ModelDto AsDto(Model model) => new ModelDto { ModelId = model.ModelId, ModelName = model.ModelName, ChildModels = model.ChildModels.AsQueryable().Select(ChildModel.AsDto).ToList(), AnotherChildModel = new AnotherChildModelDto { AnotherChildModelId = model.AnotherChildModelId } }
查询可以简化为:
dbContext.Models .Where(m => SomeCriteria).Select(m => Model.AsDto(m)) .Decompile() .ToList();
每个库都实现了目标通过在 EF Core 处理之前修改表达式树,从而避免重复代码。此外,这三个都需要调用来注入各自的 IQueryProvider。
以上是用于从子属性中选择自定义 DTO 的 EF Core 代码能否高效重用?的详细内容。更多信息请关注PHP中文网其他相关文章!