【问题标题】:iterate over fields using linq使用 linq 遍历字段
【发布时间】:2011-08-22 05:34:27
【问题描述】:

我有一个包含很多列的表,我想将一行中的所有字符串字段连接在一起,这样我就可以通过它执行搜索,而无需依次将搜索字符串与每个字段进行比较。

如何在不明确说明每个列名的情况下遍历行?

ColumnA | ColumnB | ... | ColumnN
---------------------------------
   A    |    B    | ... |    N   

我想得到结果 AB...N

这是我目前所拥有的

string searchString = "text";
var searchCandidate = ATable.Where( ... condition ...); // IQueryable<ATable>
searchCandidate. // what goes here to loop through all fields ?

【问题讨论】:

  • 请显示您当前拥有的代码。您的表在哪个数据结构中?
  • 不确定我是否理解正确,但我已经在 q.. 中添加了一些信息。
  • ATable 来自什么上下文? LINQ2SQL?英孚? DataTable? ...?
  • 是linq to sql,linqpad显示的数据类型是System.Data.Linq.Table。
  • 如果表示实体 (=row) 的类没有公开列值数组,那么您对传统方法不走运......

标签: c# linq linqpad


【解决方案1】:

您可以通过如下构建表达式树来编写这样的方法:

Expression<Func<T, bool>> AnyColumnContains<T> (string value)
{
    var p = Expression.Parameter (typeof (T), "entity");

    var fieldAccessors = typeof (T)
        .GetFields()
        .Where (f => f.FieldType == typeof (string))
        .Select (f => Expression.Field (p, f))
        .ToArray();

    var fieldArray = Expression.NewArrayInit (typeof (string), fieldAccessors); 

    var concatCall = Expression.Call (typeof (string).GetMethod (
        "Concat", new[] { typeof (string[]) }), fieldArray);

    var contains = Expression.Call (
        concatCall, 
        typeof (string).GetMethod ("Contains", new[] { typeof (string) } ),
        Expression.Constant (value));

    return Expression.Lambda<Func<T, bool>> (contains, p);
}

首先,我们从实体类型中获取所有字段(LINQPad 使用字段来表示列;您可以将其更改为 GetProperties for DataContexts 在 Visual Studio 中生成)。

我们需要创建一个表达式,将这些字段输入到 string.Concat 语句中。由于后者接受一个字符串数组,我们创建一个 NewArrayInit 表达式来构建数组。

接下来,我们调用 Concat 方法将字符串连接在一起,最后调用 string.Contains 方法来测试字符串字面量是否在我们构建的表达式中。

该方法在 AdventureWorks 上的运行方式如下:

void Main()
{
    Addresses.Where (AnyColumnContains<Address> ("Seattle")).Dump();
}

Lambda 翻译:

Addresses
   .Where (
      entity => 
         String
            .Concat (new String[] { entity.AddressLine1, entity.AddressLine2,
                                    entity.City, entity.PostalCode } )
            .Contains ("Seattle")
   )

SQL 翻译:

-- Region Parameters
DECLARE @p0 NVarChar(1000) = '%Seattle%'
-- EndRegion
SELECT [t0].[AddressID], [t0].[AddressLine1], [t0].[AddressLine2], [t0].[City],
       [t0].[StateProvinceID], [t0].[PostalCode], [t0].[rowguid] AS [Rowguid],
       [t0].[ModifiedDate]
FROM [Person].[Address] AS [t0]
WHERE ((([t0].[AddressLine1] + [t0].[AddressLine2]) + [t0].[City]) + [t0].[PostalCode])
      LIKE @p0

【讨论】:

  • 这绝对是在正确的道路上,我仍然需要弄清楚如何处理空字段和非字符串字段,但这是家庭作业,所以我可以学习如何使用表达式树。谢谢乔! :)
【解决方案2】:

试试这个:

    private void Form1_Load(object sender, EventArgs e)
    {
        DataTable dt = new DataTable();
        dt.Columns.Add(new DataColumn { DataType = typeof(int), ColumnName = "A" });
        dt.Columns.Add(new DataColumn { DataType = typeof(int), ColumnName = "b" });
        dt.Columns.Add(new DataColumn { DataType = typeof(string), ColumnName = "c" });
        DataRow r;
        for (int i=0;i<=5 ;i++)
        {
            r = dt.NewRow();
            r["A"] = i;
            r["b"] = i + 2;
            r["c"] = i.ToString();
            dt.Rows.Add(r);

        }
        var query = from DataRow row in dt.Rows.Cast<DataRow>().ToList()
                    let textUnion = GetFields(row)
                    select new { textUnion };
        dataGridView1.DataSource = query.ToList();

    }
    string GetFields(DataRow row)
    {
        StringBuilder retValue=new StringBuilder();

        for (int i = 0; i < row.ItemArray.Length;i++ )
        {
            retValue.Append(Convert.ToString(row[i]));
        }

        return retValue.ToString();
    }

【讨论】:

  • 嗯...问题是,我的不是数据表。它的类型是 System.Linq.IQueryable。
  • 我不确定它是如何声明的,我使用的是 linqpad,它会在内部创建对象。我只是使用它制作的 linqtosql 表
【解决方案3】:

如果您将每一行作为列值的数组,您可以使用AggregateDataTable 就是这种情况。

【讨论】:

  • 我只设法使用聚合函数在一个字段中遍历许多不同的行,因此可以说是一列。你如何迭代一行?还是连续多个字段?
  • @Joe:正如我在对您的问题的评论中所说,这只有在每行都将其值公开为数组时才有可能。
猜你喜欢
  • 2016-02-06
  • 2022-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-27
  • 1970-01-01
相关资源
最近更新 更多