我试图得到一个表达式树访问者添加一个连接到另一个表时,某些实体查询。如果我包含一个投射到匿名类型的.Select()
方法,并直接指定正在查询的特定实体的列,则表达式将非常有效:
var joinEntity = expression.Target.EntityContainer.BaseEntitySets.Single(s => s.Name == "TestJoinTable");
return expression.InnerJoin(
DbExpressionBuilder.Scan(joinEntity),
(l, r) => DbExpressionBuilder.And(
DbExpressionBuilder.Equal(
DbExpressionBuilder.Property(l, "JoinId"),
DbExpressionBuilder.Property(r, "JoinId")
)
, DbExpressionBuilder.Equal(
DbExpressionBuilder.Property(r, "UserId"),
DbExpression.FromInt32(_userId)
)
)
)
.Select(exp =>
new { // these are the 3 columns from one specific entity I have called Resources
ResourceId = exp.Property("l").Property("ResourceId"),
ResourceName = exp.Property("l").Property("ResourceName"),
JoinId = exp.Property("l").Property("JoinId"),
}
);
在这种特殊情况下导致这个表达式逻辑运行的LINQ to entities查询是:
List<Resource> resources = db.Resources.ToList();
问题是,表达式访问器代码旨在针对许多不同的实体查询运行,而不仅仅是针对资源实体查询。我需要一个动态的方式来选择所有列从左边的实体。我需要指定如下内容:
.Select( exp => exp.Property("l").Property("*") )
上面的表达式不能编译。它抛出错误:No property with the name '*' is declared by the type 'ScratchDbModel.Store.Resource'
.
我也试过了,但是它失败了,出现了类似的错误信息:
.Select( exp => exp.Property("l.*") )
我试着只选择左边的实体,像这样:
.Select( exp => exp.Property("l") )
上面的表达式编译后看起来很有希望,直到它实际运行查询,结果如下SQL:
SELECT
[Extent1].[ResourceId] AS [ResourceId],
[Extent1].[ResourceName] AS [ResourceName],
[Extent1].[JoinId] AS [JoinId]
FROM ( SELECT [l]
FROM [dbo].[Resource] AS [l]
INNER JOIN [sec].[TestJoinTable] AS [r]
ON ([l].[JoinId] = [r].[JoinId]) AND ([r].[UserId] = 2)
) AS [Extent1]
由于内部SELECT选择的是[l]
而不是[l.*]
或列名列表,因此查询执行失败,并显示以下消息:
Invalid column name 'l'.
Invalid column name 'ResourceId'.
Invalid column name 'ResourceName'.
Invalid column name 'JoinId'.
我已经尝试了许多不同的事情,但似乎不知道如何做到这一点。如果我完全离开.Select()
,我收到错误:
An exception of type 'System.ArgumentOutOfRangeException' occurred in EntityFramework.dll but was not handled in user code
Additional information: No property with the name 'ResourceId' is declared by the type 'Transient.rowtype[(l,ScratchDbModel.Store.Resource(Nullable=True,DefaultValue=)),(r,ScratchDbModel.Store.TestJoinTable(Nullable=True,DefaultValue=))]'.
当然,这是因为实体框架期望接收IEnumerable<Resource>
,而不是一些多表连接结果。
是否有任何方法可以通用地指定"左表的所有列"或创建某种类型的动态匿名类型或动态投影,其中包含左实体的所有列引用?
要选择属性的所有属性,只需选择它的整体:
return expression.InnerJoin(
DbExpressionBuilder.Scan(joinEntity),
(l, r) => DbExpressionBuilder.Equal(
DbExpressionBuilder.Property(l, "JoinId"),
DbExpressionBuilder.Property(r, "JoinId")
)
)
.Select(exp => exp.Property("l"));
这将自动生成查询,选择"l"拥有的所有列。