C# 如何按主键或任何默认值进行排序,以允许跳过并接受泛型集合上的EF?

C# 如何按主键或任何默认值进行排序,以允许跳过并接受泛型集合上的EF?,c#,reflection,entity-framework-6,C#,Reflection,Entity Framework 6,我有一个方法,它采用了IQueryable,我在它上面做了一些通用的东西。通常会指定order属性,这很好,但有时没有提供任何内容,我需要通过某种方式对其进行排序,以便应用skip/take 我会很高兴在主键上这样做,但任何能起作用的东西都是好的 但我似乎无法从IQueryable集合中获取主键。我尝试了一些我在网上找到的代码来循环使用PropertyInfo[]properties=typeof(T).GetProperties()属性和GetCustomAttributes()但是似乎根本没

我有一个方法,它采用了
IQueryable
,我在它上面做了一些通用的东西。通常会指定order属性,这很好,但有时没有提供任何内容,我需要通过某种方式对其进行排序,以便应用skip/take

我会很高兴在主键上这样做,但任何能起作用的东西都是好的

但我似乎无法从
IQueryable
集合中获取主键。我尝试了一些我在网上找到的代码来循环使用
PropertyInfo[]properties=typeof(T).GetProperties()属性和
GetCustomAttributes()
但是似乎根本没有任何属性

我正在使用此方法,但它只给了我
null

private PropertyInfo GetPrimaryKeyInfo<T>()
{
    PropertyInfo[] properties = typeof(T).GetProperties();
    foreach (PropertyInfo pI in properties)
    {
        System.Object[] attributes = pI.GetCustomAttributes(true);
        foreach (object attribute in attributes)
        {
            if (attribute is EdmScalarPropertyAttribute)
            {
                if ((attribute as EdmScalarPropertyAttribute).EntityKeyProperty == true)
                    return pI;
            }
            else if (attribute is System.Data.Linq.Mapping.ColumnAttribute)
            {

                if ((attribute as System.Data.Linq.Mapping.ColumnAttribute).IsPrimaryKey == true)
                    return pI;
            }
        }
    }
    return null;
}
私有属性信息GetPrimaryKeyInfo() { PropertyInfo[]properties=typeof(T).GetProperties(); foreach(PropertyInfo pI in properties) { System.Object[]attributes=pI.GetCustomAttributes(true); foreach(属性中的对象属性) { if(属性为EdmScalarPropertyAttribute) { if((属性为EdmScalarPropertyAttribute).EntityKeyProperty==true) 返回pI; } else if(属性为System.Data.Linq.Mapping.ColumnAttribute) { if((属性为System.Data.Linq.Mapping.ColumnAttribute).IsPrimaryKey==true) 返回pI; } } } 返回null; }
我可以在我的实体模型中看到,对于我正在使用的T实例,有一个主键集


有人能提供建议吗?

您可以从EF元数据(不是很直观)中获得这些信息。例如,以下内容将返回PK属性名称,然后您可以简单地使用反射或
Expression.property
生成必要的访问器/表达式:

static IEnumerable<string> GetPrimaryKeyNames<TEntity>(DbContext dbContext)
    where TEntity : class
{
    var entityType = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dbContext).ObjectContext
        .CreateObjectSet<TEntity>().EntitySet.ElementType;
    return entityType.KeyProperties.Select(p => p.Name);
}
静态IEnumerable GetPrimaryKeyNames(DbContext DbContext)
地点:班级
{
var entityType=((System.Data.Entity.Infrastructure.IOObjectContextAdapter)dbContext).ObjectContext
.CreateObjectSet().EntitySet.ElementType;
返回entityType.KeyProperties.Select(p=>p.Name);
}

您可以扩展域模型,为所有实体添加一个接口,而不是使用反射,这样可以帮助您使用通用代码,例如:

public interface IEntity
{
    int Id { get; set; }
}
然后您可以编写一些通用方法,如:

public void Update<T>(IQueryable<T> query, Expression<Func<T, object>> orderBy = null)
    where T : IEntity
{
    if (orderBy == null)
        query = query.OrderBy(m => m.Id);
    else
        query = query.OrderBy(orderBy);
}
公共无效更新(IQueryable查询,表达式orderBy=null)
其中T:
{
if(orderBy==null)
query=query.OrderBy(m=>m.Id);
其他的
query=query.OrderBy(OrderBy);
}

此解决方案取决于实体的外观、它们具有何种不同的键以及是否可以将它们统一到一个或多个接口。

EF6抱歉-我已更新了标记问题在于我无法访问此方法中的上下文,我只有一个
IQueryable
。然后您需要以某种方式将该信息传递给该方法。或者使用我的答案中的(有点黑)方法。您知道如何将参数传递给该方法,例如类似于
()=>myEntity.EntityId的内容,以便我可以使用它吗?如何指定该方法的order属性?可能是表达式或字符串?我想无论您对sort属性使用了什么,您都可以将其用于此目的。我现在正在执行
collection.OrderByDescending(Expression.Lambda(sortSelectorParameter))
(对于字符串提供的排序),但是如果我可以传入
c=>c.CustomerId
,那么最好使用强类型。。。我想我只是通过了一个
Func
然后?但我不知道那是什么。