Jas*_*rez 10 c# linq generics linq-to-entities
我有一个简单的扩展方法,用于按标签过滤LINQ IQueryable.我正在使用LINQ to Entities,接口为:
public interface ITaggable
{
ICollection<Tag> Tags { get; }
}
Run Code Online (Sandbox Code Playgroud)
以下不起作用,返回IQueryable<ITaggable>而不是IQueryable<T>:
public static IQueryable<T> WhereTagged<T>(this IQueryable<T> set, string tag) where T:ITaggable
{
return set.Where(s=>s.Tags.Any(t=>t.Name.ToLower() == tag.ToLower()));
}
Run Code Online (Sandbox Code Playgroud)
这导致LINQ to Entities强制转换异常:
"无法将类型'ReleaseGateway.Models.Product'转换为'ReleaseGateway.Models.ITaggable'.LINQ to Entities仅支持转换实体数据模型基元类型." (System.NotSupportedException)捕获到System.NotSupportedException:"无法将类型'Project.Models.Product'强制转换为'Project.Models.ITaggable'.LINQ to Entities仅支持转换实体数据模型基元类型."
它没有像这样的约束,但我必须在我的应用程序代码中显式声明类型T:
public static IQueryable<T> WhereTagged<T>(this IQueryable<ITaggable> set, string tag)
{
return set.Where(s=>s.Tags.Any(t=>t.Name.ToLower() == tag.ToLower())).Cast<T>();
}
Run Code Online (Sandbox Code Playgroud)
问题:为什么类型约束会转换返回类型?我可以重写这个以利用扩展方法调用者推断类型吗?
我怀疑这个问题来自于呼吁s.Tags.因为s是a Product,但是你正在调用ITaggable.Tags,生成的表达式看起来更像:
set.Where(s=>((ITaggable)s).Tags.Any(...))
Run Code Online (Sandbox Code Playgroud)
这只会混淆实体框架.试试这个:
((IQueryable<ITaggable>)set)
.Where(s=>s.Tags.Any(t=>t.Name.ToLower() == tag.ToLower()))
.Cast<T>();
Run Code Online (Sandbox Code Playgroud)
由于IQueryable是一个协变接口,这将把集合视为一个IQueryable<ITaggable>,它应该工作,因为你的第二个例子基本上完全相同的事情.
我一直在寻找相同的答案,并且对所提供的答案的语法简洁性不满意,我一直在寻找并找到了这篇文章。
太长;博士;-将类添加到您的约束中并且它可以工作。
LINQ to Entities 仅支持使用 IEntity 接口转换 EDM 基元或枚举类型
public static IQueryable<T> WhereTagged<T>(this IQueryable<T> set, string tag)
where T: class, ITaggable
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1459 次 |
| 最近记录: |