在一对多 Entity Framework 关系中使用 Dynamic LINQ Where
Using Dynamic LINQ Where in a one-to-many Entity Framework relationship
我正在使用 EF 6 和 .net 4.5。
我有一个 "Documents" table 和 PK "DocumentId" (Int) 和另一列 "Title"。我有另一个名为 "DocumentFilters" 的 table,其列为 "DocumentId"(Int)和 "DocGUID"(Guid)。两个 table 之间的 "Doc Id" 上有一个 FK。它是 Documents 和 DocumentFilters tables 之间的一对多 Id 关系。模型看起来像这样:
我正在尝试使用 NuGet 包中的 DynamicLibrary.cs 库编写动态 LINQ 查询。
使用常规 Linq,查询在 c# 中看起来像这样:
DocDBContext db = new DocDBContext();
var documents = db.Documents.Include(d => d.DocumentFilters);
Guid gTest = Guid.Parse("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
documents = documents.Where(d => d.DocumentFilters.Select(f => f.DocGUID).Contains(gTest));
这非常有效,可以检索由我感兴趣的 GUID 过滤器分隔的文档。但是,我需要将它动态地放置在过滤器字符串中,其中可能包含其他过滤器。有可能这样做吗?我试过这样的代码:
documents = documents.Where("DocumentFilters.Select(DocGUID).Contains(@0)", gTest);
错误:不存在适用的聚合方法'Select'
或
documents = documents.Where("DocumentFilters.DocGUID=@0", gTest);
错误:GUID 属性 在 DocumentFilters 上不存在。
(这是有道理的,因为 DocumentFilters 是一个集合)。
我也认为可能值得试一试:
documents = documents.Where("DocumentFilters.AsQueryable().Select(DocGUID).Contains(@0)", gTest);
但同样,它看起来不像库支持 AsQueryable 并抛出
错误:不存在适用的聚合方法 'AsQueryable'。
是否可以在文档 table 中对可枚举对象的 属性 写入这样的限制?
尝试使用Dynamic Linq,可以对字符串使用
所以一种解决方案是修改Dynamic.cs,在ExpressionParser
的IEnumerableSignatures
接口中添加“Select” class。并将其添加到 ParseAggregate()
方法中:
if (signature.Name == "Min" || signature.Name == "Max")
{
typeArgs = new Type[] { elementType, args[0].Type };
}
else if (signature.Name == "Select")
{
typeArgs = new Type[] { elementType, Expression.Lambda(args[0], innerIt).Body.Type };
}
但是,在此之后我仍然需要重载 Contains()
方法来使用 GUID。我懒得那样做。相反,我意识到我可以简单地使用已经支持的 .Any()
而不是 .Select()
!
documents = documents.Where("DocumentFilters.Any(DocGUID.Equals(@0))", gTest); //!!!
我还必须将列名称从“GUID”更改为“DocGUID”,因为在写入 GUID.Equals()
时限制字符串,解析器将其误认为是 GUID 类型而不是列名,并抛出 Equals()
不是 GUID 类型的有效扩展名的错误。
抱歉浪费了大家的时间!
我正在使用 EF 6 和 .net 4.5。 我有一个 "Documents" table 和 PK "DocumentId" (Int) 和另一列 "Title"。我有另一个名为 "DocumentFilters" 的 table,其列为 "DocumentId"(Int)和 "DocGUID"(Guid)。两个 table 之间的 "Doc Id" 上有一个 FK。它是 Documents 和 DocumentFilters tables 之间的一对多 Id 关系。模型看起来像这样:
我正在尝试使用 NuGet 包中的 DynamicLibrary.cs 库编写动态 LINQ 查询。
使用常规 Linq,查询在 c# 中看起来像这样:
DocDBContext db = new DocDBContext();
var documents = db.Documents.Include(d => d.DocumentFilters);
Guid gTest = Guid.Parse("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
documents = documents.Where(d => d.DocumentFilters.Select(f => f.DocGUID).Contains(gTest));
这非常有效,可以检索由我感兴趣的 GUID 过滤器分隔的文档。但是,我需要将它动态地放置在过滤器字符串中,其中可能包含其他过滤器。有可能这样做吗?我试过这样的代码:
documents = documents.Where("DocumentFilters.Select(DocGUID).Contains(@0)", gTest);
错误:不存在适用的聚合方法'Select'
或
documents = documents.Where("DocumentFilters.DocGUID=@0", gTest);
错误:GUID 属性 在 DocumentFilters 上不存在。 (这是有道理的,因为 DocumentFilters 是一个集合)。
我也认为可能值得试一试:
documents = documents.Where("DocumentFilters.AsQueryable().Select(DocGUID).Contains(@0)", gTest);
但同样,它看起来不像库支持 AsQueryable 并抛出 错误:不存在适用的聚合方法 'AsQueryable'。
是否可以在文档 table 中对可枚举对象的 属性 写入这样的限制?
尝试使用Dynamic Linq,可以对字符串使用
所以一种解决方案是修改Dynamic.cs,在ExpressionParser
的IEnumerableSignatures
接口中添加“Select” class。并将其添加到 ParseAggregate()
方法中:
if (signature.Name == "Min" || signature.Name == "Max")
{
typeArgs = new Type[] { elementType, args[0].Type };
}
else if (signature.Name == "Select")
{
typeArgs = new Type[] { elementType, Expression.Lambda(args[0], innerIt).Body.Type };
}
但是,在此之后我仍然需要重载 Contains()
方法来使用 GUID。我懒得那样做。相反,我意识到我可以简单地使用已经支持的 .Any()
而不是 .Select()
!
documents = documents.Where("DocumentFilters.Any(DocGUID.Equals(@0))", gTest); //!!!
我还必须将列名称从“GUID”更改为“DocGUID”,因为在写入 GUID.Equals()
时限制字符串,解析器将其误认为是 GUID 类型而不是列名,并抛出 Equals()
不是 GUID 类型的有效扩展名的错误。
抱歉浪费了大家的时间!