不知道我正在嘗試的是否可能,但我想在對象父屬性上重用linq表達式。Linq - 在子屬性上重用表達式
在給定的類:
class Parent {
int Id { get; set; }
IList<Child> Children { get; set; }
string Name { get; set; }
}
class Child{
int Id { get; set; }
Parent Dad { get; set; }
string Name { get; set; }
}
如果我再有一個幫手
Expression<Func<Parent,bool> ParentQuery() {
Expression<Func<Parent,bool> q = p => p.Name=="foo";
}
然後我想查詢出的子數據時使用此,沿着線:
using(var context=new Entities.Context) {
var data=context.Child.Where(c => c.Name=="bar"
&& c.Dad.Where(ParentQuery));
}
我知道我可以做到兒童收藏:
using(var context=new Entities.Context) {
var data=context.Parent.Where(p => p.Name=="foo"
&& p.Childen.Where(childQuery));
}
但不能看到任何方式對一個屬性不是集合做到這一點。
這只是一個簡化的例子,實際上,ParentQuery將會更加複雜,我想避免在多個地方重複這個操作,而不是隻有兩層,我會接近5或6,但是他們都需要引用父查詢以確保安全性。
如果這不可能,我的另一個想法是以某種方式將ParentQuery表達式有效地轉換爲給定類型: p => p.Name ==「foo」;變成: c => c.Dad.Name ==「foo」; ,但使用泛型/一些其他形式的查詢生成器,它允許這保留父查詢,然後只需構建一個翻譯器每個子對象替代在屬性路由到父。
編輯: 通過@大衛·莫頓
從評論繼最初看起來像我剛剛從表達式更改爲委託函數,然後調用 。凡(ParentQuery()(C。爸));
但是我在更廣泛的存儲庫模式中使用它,並且不知道如何將它用於泛型和謂詞構建器 - 我不想從存儲中檢索行並在客戶端(本例中爲web服務器)上進行過濾。我有一個通用的get數據方法,它接受基礎表達式查詢。然後我想測試一下,看看提供的類型是否實現了ISecuredEntity,以及它是否爲我們正在處理的實體附加了安全查詢。
public static IList<T> GetData<T >(Expression<Func<T, bool>> query) {
IList<T> data=null;
var secQuery=RepositoryHelperers.GetScurityQuery<T>();
if(secQuery!=null) {
query.And(secQuery);
}
using(var context=new Entities.Context()) {
var d=context.GetGenericEntitySet<T>();
data=d.ToList();
}
return data;
}
ISecuredEntity:
public interface ISecuredEntity : IEntityBase {
Expression<Func<T, bool>> SecurityQuery<T>();
}
例實體:
public partial class ExampleEntity: ISecuredEntity {
public Expression<Func<T, bool>> SecurityQuery<T>() {
//get specific type expression and make generic
Type genType = typeof(Func<,>).MakeGenericType(typeof(ExampleEntity), typeof(bool));
var q = this.SecurityQuery(user);
return (Expression<Func<T, bool>>)Expression.Lambda(genType, q.Body, q.Parameters);
}
public Expression<Func<ExampleEntity, bool>> SecurityQuery() {
return e => e.OwnerId==currentUser.Id;
}
}
和repositoryHelpers:
internal static partial class RepositoryHelpers {
internal static Expression<Func<T, bool>> SecureQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>();
}
return null;
}
}
EDIT這裏是(最終)解決方案
我最終回到使用表達式,並使用LinqKit Invoke。注意:對於EF我也必須打電話。AsExpandable()在EntitySet的
的關鍵部分是能夠撥打:
Product.SecureFunction(user).Invoke(pd.ParentProduct);
,這樣我可以在上下文傳遞到我的父查詢
我的最終類的樣子:
public interface ISecureEntity {
Func<T,bool> SecureFunction<T>(UserAccount user);
}
public class Product : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Expression<Func<Product,bool>> SecureFunction(UserAccount user) {
return f => f.OwnerId==user.AccountId;
}
public string Name { get;set; }
public string OwnerId { get;set; }
}
public class ProductDetail : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Func<ProductDetail,bool> SecureFunction(UserAccount user) {
return pd => Product.SecureFunction(user).Invoke(pd.ParentProduct);
}
public int DetailId { get;set; }
public string DetailText { get;set; }
public Product ParentProduct { get;set; }
}
用法:
public IList<T> GetData<T>() {
IList<T> data=null;
Expression<Func<T,bool>> query=GetSecurityQuery<T>();
using(var context=new Context()) {
var d=context.GetGenericEntitySet<T>().Where(query);
data=d.ToList();
}
return data;
}
private Expression<Func<T,bool>> GetSecurityQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>(GetCurrentUser());
}
return a => true; //returning a dummy query
}
}
感謝您的幫助。
啊 - 那是偉大的,幾乎我想要做什麼。 我正在使用LinqKut在ParentQuery中構建epression,因此Expression
steve
好,幾乎有.. 我在執行,ParentQuery實際上是宣佈在接口上爲公衆Func鍵 SecurityQuery () 我以前然後通過Expression.Lambda建立一個通用的表達式返回一個強類型的查詢()。 如果我有公共Func SecurityQuery()如何將其轉換爲Func ? 當然,有一種簡單的方法,我失蹤了? –
steve
已經做了一些更多的測試,這是我的最後一道關口 - 如何將fet Func轉換爲Func (在運行時,T將是父項) –
steve