Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在代码优先EF存储库中将动态表达式传递给order by_C#_Linq_Entity Framework - Fatal编程技术网

C# 在代码优先EF存储库中将动态表达式传递给order by

C# 在代码优先EF存储库中将动态表达式传递给order by,c#,linq,entity-framework,C#,Linq,Entity Framework,我们编写了一个通用函数,以在存储库模式中首先从EF代码中获取记录。Rest似乎还可以,但当将整数传递给动态order by时,它表示无法将System.Int32强制转换为System.Object 表达方式如下: Expression<Func<HeadOffice, object>> orderByFunc = o => o.Id; if (options.sort == "Id") { // this is an Integer

我们编写了一个通用函数,以在存储库模式中首先从EF代码中获取记录。Rest似乎还可以,但当将整数传递给动态order by时,它表示
无法将System.Int32强制转换为System.Object

表达方式如下:

Expression<Func<HeadOffice, object>> orderByFunc = o =>  o.Id;

if (options.sort == "Id")
{
         // this is an Integer
    orderByFunc = o => o.Id;
}
if (options.sort =="Name")
{
   // string
    orderByFunc = o => o.Name;
}
if (options.sort == "Code")
{
    orderByFunc = o => o.Code;
}
public virtual IEnumerable<TEntity> GetSorted<TSortedBy>(
    Expression<Func<TEntity, object>> order,
    int skip, int take, 
    params Expression<Func<TEntity, object>>[] includes)
{
    IQueryable<TEntity> query = dbSet;

    foreach (var include in includes)
    {
        query = dbSet.Include(include);
    }

    IEnumerable<TEntity> data = query.OrderBy(order).Skip(skip).Take(take).ToList();

    return data;
}
表达式orderByFunc=o=>o.Id; 如果(options.sort==“Id”) { //这是一个整数 orderByFunc=o=>o.Id; } if(options.sort==“Name”) { //串 orderByFunc=o=>o.Name; } if(options.sort==“Code”) { orderByFunc=o=>o.代码; } 一般方法如下:

Expression<Func<HeadOffice, object>> orderByFunc = o =>  o.Id;

if (options.sort == "Id")
{
         // this is an Integer
    orderByFunc = o => o.Id;
}
if (options.sort =="Name")
{
   // string
    orderByFunc = o => o.Name;
}
if (options.sort == "Code")
{
    orderByFunc = o => o.Code;
}
public virtual IEnumerable<TEntity> GetSorted<TSortedBy>(
    Expression<Func<TEntity, object>> order,
    int skip, int take, 
    params Expression<Func<TEntity, object>>[] includes)
{
    IQueryable<TEntity> query = dbSet;

    foreach (var include in includes)
    {
        query = dbSet.Include(include);
    }

    IEnumerable<TEntity> data = query.OrderBy(order).Skip(skip).Take(take).ToList();

    return data;
}
公共虚拟IEnumerable GetSorted( 表达顺序, 整数跳过,整数取, 参数表达式[]包括) { IQueryable query=dbSet; foreach(包含在包含中的var) { query=dbSet.Include(Include); } IEnumerable data=query.OrderBy(order).Skip(Skip).Take(Take).ToList(); 返回数据; } 如果我们将
Expression
转换为
Expression
,那么它似乎可以很好地处理整数,但因此不能处理字符串


感谢您的帮助。

一种解决方案是使用两种重载方法,一种是

Expression<Func<TEntity, int>>
Expression<Func<TEntity, string>>
表达式
一个接一个

Expression<Func<TEntity, int>>
Expression<Func<TEntity, string>>
表达式

为了最大限度地减少代码重复,请将公共代码(例如查询初始化语句和for循环)提取到共享方法,然后让这两个方法调用此共享方法,然后对结果调用OrderBy。

如果您更改此
Func OrderBy的参数类型,则可能,它可以让你的生活更轻松:

public virtual IEnumerable<TEntity> GetSorted(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy,...)
{
    IQueryable<TEntity> query = dbSet;
    //...
    if (orderBy != null)
    {
        query = orderBy(query);
    }
    //...
}
更新 我现在注意到的另一件事是,您没有使用
TSortedBy
generic参数,因此,您也可以这样做:

public virtual IEnumerable<TEntity> GetSorted<TSortedBy>(Expression<Func<TEntity, TSortedBy>> order,
                                                         int skip, int take, 
                                                         params Expression<Func<TEntity, object>>[] includes)
{
}
公共虚拟IEnumerable GetSorted(表达式顺序,
整数跳过,整数取,
参数表达式[]包括)
{
}

但无论如何,我认为最好使用第一个选项并删除该泛型参数。

创建一个Sorter类。我们还需要一个属性类型中性基类:

public class SorterBase<TEntity>
{                                                               
    public abstract IEnumerable<TEntity> GetSorted( // Note, no order argument here
        int skip, int take, 
        params Expression<Func<TEntity, object>>[] includes);
}

public class Sorter<TEntity, TSortProp> : SorterBase<TEntity>
{                                                               
    private Expression<Func<TEntity, TSortProp>> _order;

    public Sorter(Expression<Func<TEntity, TSortProp>> order)
    {
        _order = order;
    }

    public override IEnumerable<TEntity> GetSorted(...)
    {
       // Use _order here ...
    }
}
公共类分类数据库
{                                                               
公共抽象IEnumerable GetSorted(//注意,这里没有顺序参数
整数跳过,整数取,
参数表达式[]包括);
}
公共类分拣机:SorterBase
{                                                               
私人表达秩序;
公共分拣机(表达订单)
{
_订单=订单;
}
公共重写IEnumerable GetSorted(…)
{
//在这里使用命令。。。
}
}
现在将排序决定更改为:

SorterBase<HeadOffice> sorter;
if (options.sort == "Id") {
    sorter = new Sorter<HeadOffice, int>(o => o.Id);
} else if (options.sort == "Name") {
    sorter = new Sorter<HeadOffice, string>(o => o.Name);
}
...

var result = sorter.GetSorted(skip, take, includes);
SorterBase分拣机;
如果(options.sort==“Id”){
分拣机=新分拣机(o=>o.Id);
}else if(options.sort==“Name”){
分拣机=新分拣机(o=>o.Name);
}
...
var结果=分拣机。GetSorted(跳过、取出、包括);

如果所有答案都不适用于您,您必须将顺序表达式设置为:

Expression<Func<TEntity,object>>
表达式
然后尝试以下解决方案:

public class ExpressionHelper : ExpressionVisitor
{
    private MemberExpression m_MemberExpression;

    public MemberExpression GetPropertyAccessExpression(Expression expression)
    {
        m_MemberExpression = null;

        Visit(expression);


        return m_MemberExpression;
    }

    protected override Expression VisitMember(MemberExpression node)
    {

        var property = node.Member as PropertyInfo;

        if (property != null)
        {
            m_MemberExpression = node;
        }

        return base.VisitMember(node);

    }
}

public class DataClass<TEntity>
{
    private readonly IQueryable<TEntity> m_Queryable;

    public DataClass(IQueryable<TEntity> queryable)
    {
        m_Queryable = queryable;
    }


    public virtual IEnumerable<TEntity> GetSorted(
        Expression<Func<TEntity, object>> order,
        int skip, int take,
        params Expression<Func<TEntity, object>>[] includes)
    {

        var property_access_expression = new ExpressionHelper().GetPropertyAccessExpression(order);

        if(property_access_expression == null)
            throw new Exception("Expression is not a property access expression");

        var property_info = (PropertyInfo) property_access_expression.Member;

        var covert_method = this.GetType().GetMethod("Convert").MakeGenericMethod(property_info.PropertyType);

        var new_expression = covert_method.Invoke(this, new object[] {property_access_expression, order.Parameters });


        var get_sorted_method = this.GetType()
            .GetMethod("GetSortedSpecific")
            .MakeGenericMethod(property_info.PropertyType);


        return (IEnumerable<TEntity>)get_sorted_method.Invoke(this, new object[] { new_expression, skip, take, includes });
    }

    public virtual IEnumerable<TEntity> GetSortedSpecific<TSortedBy>(
        Expression<Func<TEntity, TSortedBy>> order,
        int skip, int take,
        params Expression<Func<TEntity, object>>[] includes)
    {

        IQueryable<TEntity> query = m_Queryable;

        //Here do your include logic and any other logic

        IEnumerable<TEntity> data = query.OrderBy(order).Skip(skip).Take(take).ToList();

        return data;
    }

    public Expression<Func<TEntity, TNewKey>> Convert<TNewKey>(
        MemberExpression expression, ReadOnlyCollection<ParameterExpression> parameter_expressions )
    {
        return Expression.Lambda<Func<TEntity, TNewKey>>(expression, parameter_expressions);
    }
}
公共类ExpressionHelper:ExpressionVisitor
{
私有成员表达式m_MemberExpression;
公共成员表达式GetPropertyAccessExpression(表达式)
{
m_MemberExpression=null;
参观(表达);
返回m_MemberExpression;
}
受保护的重写表达式VisitMember(MemberExpression节点)
{
var property=node.Member作为PropertyInfo;
if(属性!=null)
{
m_MemberExpression=节点;
}
返回base.VisitMember(节点);
}
}
公共类数据类
{
私有只读可查询m_可查询;
公共数据类(IQueryable可查询)
{
m_Queryable=可查询;
}
公共虚拟IEnumerable GetSorted(
表达顺序,
整数跳过,整数取,
参数表达式[]包括)
{
var property_access_expression=new ExpressionHelper();
if(属性\访问\表达式==null)
抛出新异常(“表达式不是属性访问表达式”);
var property_info=(PropertyInfo)property_access_expression.Member;
var covert_method=this.GetType().GetMethod(“Convert”).MakeGenericMethod(property_info.PropertyType);
var new_expression=covert_method.Invoke(这个新对象[]{property_access_expression,order.Parameters});
var get_sorted_method=this.GetType()
.GetMethod(“GetSortedSpecific”)
.MakeGenericMethod(属性信息.PropertyType);
return(IEnumerable)get_sorted_方法。Invoke(this,new object[]{new_expression,skip,take,includes});
}
公共虚拟IEnumerable GetSortedSpecific(
表达顺序,
整数跳过,整数取,
参数表达式[]包括)
{
IQueryable query=m_Queryable;
//这里是否包含逻辑和任何其他逻辑
IEnumerable data=query.OrderBy(order).Skip(Skip).Take(Take).ToList();
返回数据;
}
公共表达式转换(
MemberExpression表达式,ReadOnlyCollection参数(表达式)
{
返回表达式.Lambda(表达式、参数_表达式);
}
}
下面是我如何测试的:

    void Test()
    {
        Expression<Func<Entity, object>> exp = (x) => x.Text;

        List<Entity> entities = new List<Entity>();

        entities.Add(new Entity()
        {
            Id = 1,
            Text = "yacoub"
        });


        entities.Add(new Entity()
        {
            Id = 2,
            Text = "adam"
        });


        DataClass<Entity> data = new DataClass<Entity>(entities.AsQueryable());

        var result = data.GetSorted(exp, 0, 5, null);

    }
void测试()
{
表达式exp=(x)=>x.Text;
列表实体=新列表();
实体。添加(新实体()
{
Id=1,
Text=“yacoub”
});
实体。添加(新实体()
{
Id=2,
Text=“亚当”
});
DataClass数据=新的DataClass(entities.AsQueryable());
var result=data.GetSorted(exp,0,5,null);
}
我用整数和字符串属性测试了这一点

请注意,这只适用于简单的p