시도하고있는 것이 가능한지 확실하지 않지만 개체 부모 속성에서 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 개의 레이어를 추가하는 것보다는 2 개의 레이어를 추가해야하지만 모두 상위 쿼리를 참조하여 보안을 보장합니다.
이것이 가능하지 않다면 다른 생각은 ParentQuery 표현식을 주어진 유형으로 변환하는 것이 었습니다. p => p.Name == "foo"; 은 다음으로 바뀝니다. c => c.Dad.Name == "foo"; 하지만 generics/다른 형태의 쿼리 작성기를 사용하여 상위 쿼리를 유지 한 다음 속성 경로를 상위로 대체하는 하위 개체 당 변환기를 작성해야합니다.
는편집 : 난 그냥 대리자 함수로 표현에서 변경 한 다음 어디에요 (ParentQuery() (C를 호출 할 수 있습니다처럼 는 @ 데이비드 모튼
에 의해 코멘트에 이어 처음에 그 보인다. 아빠));
그러나 더 넓은 저장소 패턴에서이를 사용하고 있으며 generics 및 predicate 빌더에서 어떻게 사용할 수 있는지 보지 못했습니다. 클라이언트의 저장소 (이 경우 웹 서버)에서 행을 검색하고 싶지 않습니다. 기본 식 쿼리를 사용하는 일반 get 데이터 메서드가 있습니다. 그런 다음 제공된 유형이 ISecuredEntity를 구현하는지, 그리고 처리중인 엔티티에 대해 securityQuery를 추가하는지 테스트하려고합니다.
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의 경우에도 전화해야했습니다.entitySet
의 핵심 부분에 AsExpandable은()를 호출 할 수있는된다
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
}
}
도움을 주셔서 감사합니다.
아 :
다음, 당신이 그것을 호출하는 방법에 전부입니다. ParentQuery 내에서 Epression을 구축하기 위해 LinqKut을 사용 했으므로 Expression
steve
좋아, 거의 다 .. 내 구현에서 이 ParentQuery 실제로 공공 Func을 SecurityQuery ()과 같은 인터페이스에 선언 이전에 그때 Expression.Lambda를 통해 일반적인 표현을 구축하여 강력한 형식의 쿼리를 반환(). 공용 Func SecurityQuery()를 어떻게 Func 으로 변환 할 수 있습니까? 내가 누락 된 쉬운 방법이 있습니까? –
steve
더 많은 테스트를 해본 결과 이것이 나의 마지막 장애물입니다 - 어떻게 Func을 Func 으로 변환 할 수 있습니까? (런타임에는 T가 부모가됩니다) –
steve