2016-09-21 109 views
2

好的我在这里有很多关于这种性质的问题,但没有一个能够完全或正确地解决这个问题。Linq to Entities and complex type casting

让我们假设我有以下代码...

public interface IHaveRoles { 
    ICollection<Role> Roles { get;set; } 
} 

public class Foo : IHaveRoles { 
    public ICollection<Role> Roles { get;set; } 
} 

public class Bar { } 

...然后我有这样的方法......

public override IQueryable<T> GetAll() 
{ 
    return base.GetAll(); 
} 
到该方法

我想添加一个检查这可能会导致我动态地添加一个简单的where子句到我的IQueryable ...

if(typeof(IHaveRoles<Role>).IsAssignableFrom(typeof(T))) { 
     return base.GetAll() 
      .Where(i => i.Roles.Any(r => r.Users.Any(u => u.Id == User.Id))); 

} 

... 这是一个非常简单的where子句,如果我知道T在设计时是什么,那么这将是一个非问题。

然而,在浇铸resultIQueryable<IHaveRoles>是不是因为当我完成追加我的条款我不能再转换回一个IQueryable<T>作为IHaveRoles一个选项不是T

那么,如何做一个子类型我们解决这个问题,同时保留返回一个IQueryable<T>并没有违法强制转换的能力,如在一些像这样的其他问题给出的答案...

Cast Entity to Implemented Interface in a Generic Method Using LINQ for Entity Framework

LINQ-to-entities casting issue

...在避免与EF不支持不EDM基本类型的问题的方式......

LINQ to Entities only supports casting EDM primitive or enumeration types with IEntity interface

编辑:一些测试,实现...

public override IQueryable<T> GetAll() 
{ 
    var result = base.GetAll(); 

    if (typeof(IHaveRoles).IsAssignableFrom(typeof(T)) && !AuthInfo.SignatureIsValid) 
    { 
     // tried implementations that don't work ... 

     // InvalidCastException (CLR can't cast an IQueryable<IHaveRoles> to a IQueryable<T> 
     var queryableRoleSecured = ((IQueryable<IHaveRoles>)result); 
     result = (IQueryable<T>)queryableRoleSecured 
      .Where(i => i.Roles.Any(r => User.Roles.Contains(r))); 

     // NotSupportedException (EF won't accept this kind of casting) 
     result = result 
      .Where(i => ((IHaveRoles)i).Roles.Any(r => r.Users.Any(u => u.Id == User.Id))); 
    } 

    return result; 
} 

回答

2

哇,我似乎从来没有得到那个动态的linq似乎没有限制,但在这里我们再次。

这就是我想出了...

public override IQueryable<T> GetAll() 
{ 
    var result = base.GetAll(); 

    if (typeof(IHaveRoles).IsAssignableFrom(typeof(T)) && !AuthInfo.SignatureIsValid) 
     result = result.Where("Roles.Any(Users.Any(Id == @0))", User.Id); 

    return result; 
} 

因为动态在运行时相同的设计时间规则并不适用于评估,这意味着我可以申请我想完全相同的LINQ(一点点当然一点的间接费用)。