简体   繁体   English

如何使用通用存储库模式按类型有条件地过滤IQueryable

[英]How to conditionally filter IQueryable by type using generic repository pattern

I have a method in my generic repository that returns an IQueryable<T> : 我的通用存储库中有一个返回IQueryable<T>

    public virtual IQueryable<T> All
    {
        get
        {
            DbSet<T> set = Context.Set<T>();

            if (typeof(T).IsSubclassOf(typeof(OrganisationDependent)))
                return set.AsEnumerable()
                          .Cast<OrganisationDependent>()
                          .Where(x => x.OrganisationID == CurrentOrganisationID)
                          .AsQueryable()
                          .Cast<T>();

            return set;
        }
    }

The reason for the if statement is that most, but not all of my tables have an OrganisationID and I want to ensure that a user only sees data for the organisation they belong to. if语句的原因是大多数但不是所有表都有一个OrganisationID ,我想确保用户只能看到他们所属组织的数据。 The above code works but in order to make it work I had to add the AsEnumerable() to pull the data into memory. 上面的代码工作,但为了使它工作,我不得不添加AsEnumerable()将数据拉入内存。 Without it I get the error message 没有它,我收到错误消息

"Unable to cast the type 'Models.xxx' to type 'Models.OrganisationDependent'. LINQ to Entities only supports casting EDM primitive or enumeration types" “无法将类型'Models.xxx'转换为'Models.OrganisationDependent'类型.LINQ to Entities仅支持转换EDM原语或枚举类型”

All my entities directly inherit either ModelBase or OrganisationDependent : 我的所有实体都直接继承ModelBaseOrganisationDependent

public abstract class OrganisationDependent : ModelBase
{
    public int OrganisationID { get; set; }

    public virtual Organisation Organisation { get; set; }
}

public abstract class ModelBase
{
    public int ID { get; set; }
}

Is there a way that I can overcome this restriction so that when the type is a sub class of OrganisationDependent , I filter on OrganisationID without having to pull the query into memory? 有没有办法可以克服这个限制,以便当类型是OrganisationDependent的子类时,我过滤OrganisationID而不必将查询拉入内存?

The simplest option is probably to use the LINQ Expressions API to build a filter expression dynamically: 最简单的选择可能是使用LINQ Expressions API动态构建过滤器表达式:

private static readonly PropertyInfo _organizationIdProperty 
    = typeof(OrganisationDependent).GetProperty("OrganisationID");

private static Expression<Func<T, bool>> FilterByOrganization<T>(int organizationId)
{
    var item = Expression.Parameter(typeof(T), "item");
    var propertyValue = Expression.Property(item, _organizationIdProperty);
    var body = Expression.Equal(propertyValue, Expression.Constant(organizationId));
    return Expression.Lambda<Func<T, bool>>(body, item);
}

public virtual IQueryable<T> All
{
    get
    {
        IQueryable<T> set = Context.Set<T>();
        if (typeof(T).IsSubclassOf(typeof(OrganisationDependent)))
        {
            var filter = FilterByOrganization<T>(CurrentOrganisationID);
            set = set.Where(filter);
        }

        return set;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM