将List <string>转换为EntityFramework列/字段列表</string>

时间:2013-04-10 09:53:32

标签: c# linq entity-framework

使用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列表将是:“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吗?我只看过使用WhereOrderBy子句的示例,但我认为我是基于这些做法正确的。

如果我的Select语法不是问题,任何人都可以看到它是什么?

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

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

2 个答案:

答案 0 :(得分:2)

您可以使用动态linq ,在here中查看。它也可以在nuget

上找到

答案 1 :(得分:2)

  

我建议dynamic linq,因为@Cuong已发布。

但是对于简单的Select投影和表达式中的手工练习......

使用How to create LINQ Expression Tree to select an anonymous type中的LinqRuntimeTypeBuilder (见那里的评论'为什么'是必要的)

添加此 ...

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等等 - 但这并不意味着涵盖所有角度(或任何真实的查询)

来自this post of mine

Deep Property Expressions