如何通过类型使用通用存储库模式有条件地过滤IQueryable [英] How to conditionally filter IQueryable by type using generic repository pattern

查看:90
本文介绍了如何通过类型使用通用存储库模式有条件地过滤IQueryable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的通用存储库中有一个方法返回一个 IQueryable< T>

  public virtual IQueryable< T>全部
{
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;
}
}

if语句的原因是最多但是不是我所有的表都有一个 OrganisationID ,我想确保用户只能看到他们所属组织的数据。上面的代码工作,但为了使其工作,我不得不添加 AsEnumerable()将数据拉入内存。没有它,我收到错误消息


无法将类型Models.xxx转换为键入
'Models.OrganisationDependent 'LINQ to Entities只支持转换
EDM原语或枚举类型


我所有的实体都直接继承 ModelBase OrganisationDependent

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

public virtual组织机构{get;组; }
}

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

有没有办法克服这个限制,是一个子类 OrganisationDependent ,我过滤 OrganisationID ,而无需将查询拉入内存?

解决方案

最简单的选择可能是使用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));
返回Expression.Lambda< Func< T,bool>>(body,item);
}

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

return set;
}
}


I have a method in my generic repository that returns an 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. The above code works but in order to make it work I had to add the AsEnumerable() to pull the data into memory. 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"

All my entities directly inherit either ModelBase or OrganisationDependent:

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?

解决方案

The simplest option is probably to use the LINQ Expressions API to build a filter expression dynamically:

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;
    }
}

这篇关于如何通过类型使用通用存储库模式有条件地过滤IQueryable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆