2016-09-21 309 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(一點點當然一點的間接費用)。