2011-05-10 61 views
2

我有一个表有很多列,并希望一起concontern在一行中的所有字符串字段,所以我可以通过它进行搜索,而无需依次比较搜索字符串与每个字段。迭代字段使用linq

如何迭代遍历行而不明确指出每个列的名称?

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 ? 
+2

请出示您当前拥有的代码。你有哪张数据结构表? – 2011-05-10 07:14:07

+0

不知道我是否正确理解了你,但是我已经向q添加了一些信息。 – Joe 2011-05-10 07:28:42

+0

从什么情况下'ATable'? LINQ2SQL? EF?一个'DataTable'? ...? – 2011-05-10 07:31:00

回答

1

您可以通过如下建立一个表达式树写这样的方法以表示列;您可以将其更改为在Visual Studio中生成的DataContexts的GetProperties)。

我们需要创建一个表达式,将这些字段提供给一个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 
+0

什么....如何....我只是失去了阴谋。消化... – Joe 2011-05-11 04:03:15

+0

这绝对是正确的路径,我仍然需要解决如何处理空字段和非字符串字段,但这是作业,所以我可以学习如何使用表达式树。谢谢乔! :) – Joe 2011-05-11 06:42:24

1

您可以使用Aggregate,如果你有每行作为一个数组列的值。 DataTable就是这种情况。

+0

我只设法使用聚合函数来遍历一个可以说许多不同的行,所以一列。你如何迭代一行?或连续的很多领域? – Joe 2011-05-10 07:41:18

+0

@Joe:正如我在你对我的问题的评论中所说的,这是唯一可能的,如果每一行都以数组形式公开它的值。 – 2011-05-10 07:46:49

+0

感谢您的意见,如果是这样的话,烦恼:P – Joe 2011-05-10 07:49:22

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使用领域:

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(); 
    } 
+0

嗡嗡声...问题是,我的数据表不是数据表。它是System.Linq.IQueryable类型的。 – Joe 2011-05-10 07:46:44

+0

@Joe,你能展示Iqueryable声明吗? – JTorrecilla 2011-05-10 07:56:50

+0

我不知道它是如何声明的,我使用linqpad并在内部创建对象。我只是使用linqtosql表,它使 – Joe 2011-05-10 12:05:58