2011-05-10 110 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