1

我想为我的列表集合应用动态项目。用户将选择注意但我的列表的属性的列。我想从 LINQ 语句中获取列的子集。我想使用动态 LINQ。any1 可以提供如何使用表达式树实现项目。我想在 Azure 表存储上应用动态投影..

我尝试实现下面的代码,它不工作,它在读取属性时抛出异常:

没有为类型“System.String”定义属性 XXXX

代码:

DataMovementDataContext dbMovement = new DataMovementDataContext();
var entity = dbMovement.ListofAccountingDocs2_1075s.AsQueryable();
Type type = entity.ElementType;
var entityParam = Expression.Parameter(entity.ElementType, "row");
Expression expr = entityParam;
string[] props = "AccountingDocumentNbr,GLCompanyCode,DocumentFiscalYearNbr".Split(',');
var epr =  GenerateMemberExpression<ListofAccountingDocs2_1075, string>("Name");

foreach (string prop in props)
{
    // use reflection (not ComponentModel) to mirror LINQ
    PropertyInfo pi = type.GetProperty(prop);
    expr = Expression.Property(expr, pi);
   //  type = pi.PropertyType; //Property 'System.String GLCompanyCode' is not defined for type 'System.String'
}

// row => row.Property
// var columnLambda = Expression.Lambda(  Expression.Property(entityParam, "GLCompanyCode"), entityParam);
var columnLambda = Expression.Lambda(Expression.Property(expr, "AccountingDocumentNbr,GLCompanyCode"), entityParam);

// Items.Select(row => row.Property)
var selectCall = Expression.Call(typeof(Queryable), "Select", new Type[] { entity.ElementType, columnLambda.Body.Type }, entity.Expression, columnLambda);

// Items.Select(row => row.Property).Distinct
var distinctCall = Expression.Call(typeof(Queryable), "Distinct", new Type[] { typeof(string) }, selectCall);

// colvalue => colvalue
var sortParam = Expression.Parameter(typeof(string), "AccountingDocumentNbr");
var columnResultLambda = Expression.Lambda(sortParam, sortParam);

// Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)
var ordercall = Expression.Call(typeof(Queryable), "OrderBy",
           new Type[] { typeof(string), columnResultLambda.Body.Type },
           distinctCall, columnResultLambda);

var result =  entity.Provider.CreateQuery(ordercall);
foreach (var item in result)
{
    Console.Write(item);
}
4

2 回答 2

3

如果您发布了您正在使用的模型的类定义,那将会更容易。

但是,您似乎正试图通过链接它们来获取多个属性。这行不通。我想你想要的是:

  new { 
      AccountingDocumentNbr = document.AccountingDocumentNbr, 
      GLCompanyCode = document.GLCompanyCode , 
      DocumentFiscalYearNbr = document.DocumentFiscalYearNbr
  };

foreach (string prop in props)循环实际上是您需要的,以便为您提供:

  document.AccountingDocumentNbr.GLCompanyCode.DocumentFiscalYearNbr

现在,它看起来像document.AccountingDocumentNbra string,因为您收到了该Property 'System.String GLCompanyCode' is not defined for type 'System.String'错误。当你这样看待它时,错误是有道理的......System.String没有GLCompanyCode属性,并且你正在构建一个链式属性表达式,它期望它有一个。还有什么可能发生?

除非您的解决方案中已经存在该类型的实例,否则您将无法获得看起来像您正在定位的匿名对象。这是因为匿名类型不是动态类型。它们可能看起来很像,但它们实际上是编译到程序集中的内部类型,并且它们的功能与具有相同成员和自定义覆盖的任何其他类没有任何不同Equals(object obj),GetHashCode()ToString()。因此,除非您有办法使用您正在寻找的定义来引用一个类,否则您将无法使用反射访问这些成员(因为它们不存在)。你最好只使用 lambda 表达式。

为了更清楚一点,下面是上面匿名类型的类定义的样子(差不多)。

public class <>f__AnonymousType0<T1,T2,T3>
{
    private readonly T1 accountingDocumentNbr;
    private readonly T2 glCompanyCode;
    private readonly T3 documentFiscalYearNbr;

    public T1 AccountingDocumentNbr
    {
        get { return accountingDocumentNbr; }
    }

    public T2 GLCompanyCode
    {
        get { return glCompanyCode; }
    }

    public T3 DocumentFiscalYearNbr
    {
        get { return documentFiscalYearNbr; }
    }

    public <>f__AnonymousType0(T1 accountingDocumentNbr, T2 glCompanyCode, T3 documentFiscalYearNbr)
    {
        this.accountingDocumentNbr = accountingDocumentNbr;
        this.glCompanyCode = glCompanyCode;
        this.documentFiscalYearNbr = documentFiscalYearNbr;
    }

    public override string ToString()
    {
        var builder = new StringBuilder();
        builder.Append("{ AccountingDocumentNbr = ");
        builder.Append(AccountingDocumentNbr);
        builder.Append(", GLCompanyCode = ");
        builder.Append(GLCompanyCode);
        builder.Append(", DocumentFiscalYearNbr = ");
        builder.Append(DocumentFiscalYearNbr);
        builder.Append(" }");
        return builder.ToString();
    }

    public override bool Equals(object value)
    {
        var type = value as <>f__AnonymousType0<T1,T2,T3>;
        return (type != null) && EqualityComparer<T1>.Default.Equals(type.AccountingDocumentNbr, AccountingDocumentNbr) && EqualityComparer<T2>.Default.Equals(type.GLCompanyCode, GLCompanyCode) && EqualityComparer<T3>.Default.Equals(type.DocumentFiscalYearNbr, DocumentFiscalYearNbr);
    }

    public override int GetHashCode()
    {
        int num = 0x7a2f0b42;
        num = (-1521134295*num) + EqualityComparer<T1>.Default.GetHashCode(AccountingDocumentNbr);
        num = (-1521134295*num) + EqualityComparer<T2>.Default.GetHashCode(GLCompanyCode);
        return (-1521134295*num) + EqualityComparer<T3>.Default.GetHashCode(DocumentFiscalYearNbr);
    }
}
于 2013-05-03T22:05:24.113 回答
0

我能够解决我的问题。

public static Expression<Func<ListofAccountingDocs2_1075, ListofAccountingDocs2_1075>> BuildExpression(string parameters)
{  
    dynamic test = new ExpandoObject();
    var sourceMembers = typeof(ListofAccountingDocs2_1075).GetProperties();

    string[] selectparams =  parameters.Split(',');//property names are comma seperated

    foreach (var item in selectparams)
      {         
          ((IDictionary<string, object>)test).Add(item,string.Empty); 
      }
    IDictionary<string,object> test2 = new Dictionary<string,object>();

    List<PropertyInfo> destinationProperties = new List<PropertyInfo>();

    foreach (var item in ((IDictionary<string, object>)test))
    {
      var selectedColumn  = typeof(ListofAccountingDocs2_1075).GetProperties().FirstOrDefault(k =>
         k.Name.Equals(item.Key));

      if (selectedColumn != null)
          destinationProperties.Add(selectedColumn);
    }

    var name = "src";

    var parameterExpression = Expression.Parameter(typeof(ListofAccountingDocs2_1075), name);

    return Expression.Lambda<Func<ListofAccountingDocs2_1075, ListofAccountingDocs2_1075>>(
        Expression.MemberInit(
            Expression.New(typeof(ListofAccountingDocs2_1075)),
            destinationProperties.Select(k => Expression.Bind(k,
                Expression.Property(
                    parameterExpression, k.Name)
                )
            ).ToArray()
            ),
        parameterExpression
    );

}
于 2013-05-04T15:39:26.803 回答