试着搜索了很多,但无法找到一个有效的答案。这就是我正在尝试做的:
我有一个实体ObjectA
,它有一个导航属性ObjectB
(不是一个集合类型,它是一个通过延迟加载加载的虚拟属性)。当我对A执行Where查询时,我还想使用MapB的另一个表达式来扩展表达式中的属性B。
这里有一些代码来演示,问题在ToObjectADto()函数中
public static Expression<Func<ObjectB, ObjectBDto>> ToObjectBDto()
{
return b => new ObjectBDto
{
Prop1 = b.Prop1,
Prop2 = b.Prop2;
};
}
public static Expression<Func<ObjectA, ObjectADto>> ToObjectADto()
{
return a => new ObjectADto
{
Name = a.Name,
SomeProperty = a.SomeProperty,
ObjectB = /* How can I call the ToObjectBDto Expression here without re-writing it? */
};
}
var aDto = _dbContext.ObjectAs.Where(q => q.SomeProperty > 0).Select(ToObjectADto());
我尝试创建一个编译表达式:
private static _toBDtoCompiled = ToObjectBDto().Compile();
然后像下面这样在ToObjectADto()
中调用它,但我得到了API Error There is already an open DataReader associated
错误,因为它是在客户端执行的。
public static Expression<Func<ObjectA, ObjectADto>> ToObjectADto()
{
return a => new ObjectADto
{
Name = a.Name,
SomeProperty = a.SomeProperty,
ObjectB = _toBDto().Invoke(a.ObjectB)
};
}
3条答案
按热度按时间6rqinv9w1#
我的建议是保存您的工作并利用AutoMapper。这里的好处是Automapper可以通过
ProjectTo
提供EF的IQueryable
实现,以构建查询并填充DTO图。任何不能在Object和DTO之间推断出的特定Map都可以在Map中设置。
ProjectTo
与自定义Map的一个优点是,它将构建相关查询,而不会触发延迟加载命中或冒触发EF无法转换为SQL的代码的风险。(一个查询即可填充所有相关DTO)Automapper可以帮助将值从DTO复制回新实体或更新现有实体:
新..
...或更新现有。
其中,DTO反映创建新对象所需的数据,或者反映允许客户端更新现有对象的数据。目标是使更新/添加/删除操作尽可能原子化,而不是传递要一次全部更新的大的复杂对象/w关系。即,诸如“AddObjectBToA”“RemoveObjectBFromA”等的动作。而不是通过单个“UpdateObjectA”来解析所有操作。
oymdgrw72#
遗憾的是,C#不处理将lambda编译成表达式,其中一个表达式调用另一个表达式。特别是因为表达式树可以表示这种情况。但是EF Core 3或更高版本无论如何都不会查看调用表达式。
Automapper可能更容易。但是如果你不想使用第三方代码,你必须自己内联表达式。包括用方法的参数替换任何
ParameterExpression
。pgccezyw3#
使用LinqKit的
.Expand()
扩展方法。Expand搜索它被调用的表达式树,并用expression
的实际内容替换内部的expression.Invoke()
方法。它允许表达式很容易地组成。举例来说: