3

使用 EntityFramework,我可以使用以下语法获取特定类型的实体列表:

List<Customer> customers = ((IQueryable<Customer>)myEntities.Customers
     .Where(c => c.Surname == strSurname)
     .OrderBy(c => c.Surname)).ToList<Customer>();

然后我可以做这样的事情来结束我感兴趣的数据:

var customerSummaries = from s in customers
     select new
     {
        s.Surname, s.FirstName, s.Address.Postcode
     };

我得到了string包含所请求的汇总数据的字段(以及必要时的表格)的列表(基于用户选择)。例如,对于上面的“customerSummary”,string提供的 s 列表将是:“Surname”、“FirstName”、“Address.Postcode”。

我的问题是:如何将该字符串列表转换为仅提取指定字段所需的语法?

如果无法做到这一点,那么对于列列表来说,什么是更好的类型(比字符串),以便我可以提取正确的信息?

如果有意义的话,我想我需要知道 EF [entity|table] 的 [member|column|field] 的类型。

编辑:

我尝试了建议的答案 - 动态 linq - 使用以下语法

string parmList = "Surname, Firstname, Address.Postcode";
var customers = myEntities.Customers.Select(parmList)
  .OrderBy("Address.Postcode");

但这会导致:EntitySqlException was unhandled. 'Surname' could not be resolved in the current scope or context. Make sure that all referenced variables are in scope, that required schemas are loaded, and that namespaces are referenced correctly.

所以,一个后续问题。我使用Select正确吗?我只看到了使用WhereandOrderBy子句的示例,但我认为基于这些我做对了。

如果我的 Select 语法不是问题,谁能看到是什么?

编辑2:它是颠倒的。这有效:

string parmList = "Surname, Firstname, Address.Postcode";
var customers = myEntities.Customers
  .OrderBy("Address.Postcode")
  .Select(parmList);
4

2 回答 2

2

您可以使用动态 linq,请在此处查看。它也可以在nuget上使用

于 2013-04-10T09:55:56.743 回答
2

我建议dynamic linq@Cuong 已经发布。

但是对于简单的Select预测和表达的手工练习......

使用LinqRuntimeTypeBuilder如何创建 LINQ 表达式树来选择匿名类型
(请参阅那里的评论以了解“为什么”是必要的)

添加这个...

public static IQueryable SelectDynamic(this IQueryable source, IEnumerable<string> fieldNames)
{
    Dictionary<string, PropertyInfo[]> sourceProperties = new Dictionary<string, PropertyInfo[]>();
    foreach (var propertyPath in fieldNames)
    {
        var props = propertyPath.Split('.');
        var name = props.Last();
        PropertyInfo[] infos;
        if (sourceProperties.TryGetValue(name, out infos))
            name = string.Join("", props);
        sourceProperties[name] = source.ElementType.GetDeepProperty(props);
    }

    Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(sourceProperties.ToDictionary(x => x.Key, x => x.Value.Last().PropertyType));

    ParameterExpression sourceItem = Expression.Parameter(source.ElementType, "t");
    IEnumerable<MemberBinding> bindings = dynamicType.GetFields()
        .Select(p => Expression.Bind(p, sourceItem.MakePropertyExpression(sourceProperties[p.Name]))).OfType<MemberBinding>();

    Expression selector = Expression.Lambda(Expression.MemberInit(
        Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem);

    MethodCallExpression selectExpression = Expression.Call(typeof(Queryable), "Select", new Type[] { source.ElementType, dynamicType }, Expression.Constant(source), selector);
    return Expression.Lambda(selectExpression).Compile().DynamicInvoke() as IQueryable;
}

public static PropertyInfo[] GetDeepProperty(this Type type, params string[] props)
{
    List<PropertyInfo> list = new List<PropertyInfo>();
    foreach (var propertyName in props)
    {
        var info = type.GetProperty(propertyName);
        type = info.PropertyType;
        list.Add(info);
    }
    return list.ToArray();
}

public static Expression MakePropertyExpression(this ParameterExpression sourceItem, PropertyInfo[] properties)
{
    Expression property = sourceItem;
    foreach (var propertyInfo in properties)
        property = Expression.Property(property, propertyInfo);
    return property;
}

像这样使用它

public static IEnumerable<object> 
    SelectAsEnumerable(this IQueryable entitySet, params string[] propertyPath)
{
    return entitySet.SelectDynamic(propertyPath) as IEnumerable<object>;
}
var list = db.YourEntity.SelectAsEnumerable("Name", "ID", "TestProperty.ID").ToList();

注意:
您可以使用类似的方法来扩展 OrderBy 等 - 但这并不意味着涵盖所有角度(或任何实际查询)

Deep Property Expressions我的这篇文章


于 2013-04-13T17:23:21.590 回答