2011-05-04 30 views
2

我已經在我的項目的方法是重複一遍又一遍:做一個搜索方法一般使用LINQ

public PAC PAC_GetByCodiPac(string codiPac) 

{ 

var sel = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac); 

      if (sel.Count() > 0) 
       return sel.First(); 
      return null; 
     } 

表PAC單元(病人),所以我有這些方法對我的所有表。 我該如何爲此製作一個通用方法? 在此先感謝。

+0

你能告訴我,_gam是什麼嗎? – 2011-05-04 07:48:58

+0

你在使用Entity Framework嗎? LINQ2SQL?還有別的嗎? – 2011-05-04 08:25:13

+0

我認爲Where()和FirstOrDefault()擴展方法已經足夠滿足您的需要 – 2011-05-04 09:01:36

回答

0

如果你想要一個通用的方法,讓你指定任何表和任何謂詞的記錄,那麼你真的不能比內建的Where<T>(...)和(如其他人已經指出的)更好擴展方法。然後

您的代碼看起來像這樣:

var result = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac).FirstOrDefault(); 
// OR 
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac); 

你能得到那麼最好的,寫自己的泛型方法,會是這樣:

public T FirstOrDefault<T>(IQueryable<T> source, 
    Expression<Func<T, bool>> predicate) 
{ 
    return source.Where(predicate).FirstOrDefault(); 
    // OR 
    // return source.FirstOrDefault(predicate); 
} 

而這其實只是多餘的。尤其是當你調用的代碼將實際上不再使用輔助方法:

var result = FirstOrDefault(_gam.PAC, pac => pac.CODI_PAC == codiPac); 
// versus 
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac); 

而且更糟的是,你的代碼不再使用流暢,組合的語法。這隻會使可讀性和維護更加困難。

如果你堅持使用IQueryable<T>擴展方法,那麼你可以做的組成是這樣的:這裏要注意

var result = _gam.PAC 
     .Where(pac => pac.CODI_PAC == codiPac) 
     .Where(pac => pac.SomeOtherProperty == someOtherValue) 
     .FirstOrDefault(); 
// OR 

var result = (from pac in _gam.PAC 
       where pac.CODI_PAC == codiPac 
       where pac.SomeOtherProperty == someOtherValue 
       select pac).FirstOrDefault(); 

其中很重要的一點是,在IQueryable<T>.Where<T>(...)擴展方法的predicate參數是Expression<Func<T, bool>>類型。這允許IQueryable<T>提供程序在返回結果之前的最後一刻構建本機SQL(或其他本地提供程序查詢)。

不使用Expression<Func<T, bool>>意味着你的查詢會是這樣的等價物:

var result = 
    _gam.PAC 
     .ToArray() 
     .Where(pac => pac.CODI_PAC == codiPac) 
     .FirstOrDefault(); 

而這將意味着該查詢將從「PAC」表中加載所有記錄到內存中,選擇第一過濾結果之前和拋出其餘的結果。

的底線是,通過使通用的輔助方法,你是重寫現有的框架代碼並打開自己性能和維護問題同時減少代碼的可讀性

我希望這會有所幫助。

+0

嗨,謝謝你的回答,你認爲上面寫的方法會比上面寫的zespri(這是通用的)還是在我的BL中有許多方法(GetByCodi使用FirstOrDefult),比如我的數據庫中的表?性能和速度會更好。 – ramo2712 2011-05-05 07:34:01

+0

@ ramo2712 - 對zespri沒有冒犯性 - 他編寫了一些非常高級的代碼,這些代碼生成的內置'Where'方法的表達性較差。我不知道爲什麼你需要在BL中使用很多方法。你的BL應該限制你只使用你應該訪問的方法 - 這意味着你不應該需要很多方法 - 或者它應該提供一種表達方式來訪問你的數據,所以標準的LINQ在那裏很好。你想達到什麼目的? – Enigmativity 2011-05-05 12:03:29

+0

我有一個項目網站和一個數據訪問庫的解決方案,其中我有GetByCodi方法。所以,不要在aspx頁面中編寫LINQ代碼,只需調用我的庫方法,並且庫增長很大(數據庫很大),所以我嘗試使用泛型方法。非常感謝您的回答。我使打印一個通用的方法,但與此我會使用此變量結果= _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac); – ramo2712 2011-05-05 14:46:31

0

我不確定你是否在問這個問題,但是這個方法可能在靜態類和方法中,所以你可以從任何地方調用它。

+1

他希望不僅爲table PAC執行此操作,還要爲其DB中的所有其他表執行此操作。 – 2011-05-04 07:54:26

+0

我不確定他的問題,但他說這種方法「一遍又一遍地重複」,我認爲它是一樣的。 – zapico 2011-05-04 09:30:33

0

一個簡單的解決方案將是:

//a generic method 
private PAC PAC_GetPAC(Func<PAC, bool> predicate) 
{ 
    return _gam.PAC.Where(predicate).FirstOrDefault(); 
} 

public PAC PAC_GetPACById(long id) 
{ 
    return PAC_GetPAC(p => p.ID == id); 
} 

public PAC PAC_GetByCodiPac(string codiPac) 
{ 
    return PAC_GetPAC(p => pac.CODI_PAC == codiPac); 
} 
+0

再次,我認爲這將只適用於表PAC,因爲_gam.PAC會給你這個特定的表。他似乎希望能夠通過表格,以便可以調用*任何*表格。 – 2011-05-04 07:58:24

1

我看到你問是一個非常簡單的where查詢甚至不需要有有它在一個單獨的方法。 你也可以簡單地提高你的查詢鏈接如下:

public PAC PAC_GetByCodiPac(string codiPac) 
{ 
    return _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac); 
} 

FirstOrDefault將返回的第一個項目的陣列上,如果沒有它會返回null。

+0

即使我不會把這個分解成每個表的獨立方法,'FirstOrDefault'是要走的路。內聯'FirstOrDefault'! – Nappy 2011-05-04 10:00:13

+0

,但有時我們必須在BL中創建簡單的方法,並且可能只包含一行,但它是一種業務方法 – 2011-05-04 10:08:13

+0

如果沒有其他方式明顯更好FirstOrDefault – ramo2712 2011-05-04 16:46:31

2

這是您的通用方法。請注意,正如其他人指出,FirstOrDefault優先於Count,然後優先,所以我在這裏使用它。但也可以編寫該表達式,以便模仿原始代碼的功能。請讓我知道你是否需要額外的幫助。

public static T GetByCodi<T>(IQueryable<T> table, string codi, string fieldName) where T : class 
{ 
    // x 
    ParameterExpression parameter = Expression.Parameter(typeof(T), "x"); 
    Expression currentExpression = parameter; 
    Type currentType = typeof(T); 
    PropertyInfo property = currentType.GetProperty(fieldName); 

    // x.CODI_xxx 
    currentExpression = Expression.Property(currentExpression, property); 

    // x.CODI_xxx == codi 
    currentExpression = Expression.Equal(currentExpression, Expression.Constant(codi)); 

    // x => x.CODI_xxx == codi 
    LambdaExpression lambdaExpression = Expression.Lambda(currentExpression, parameter); 

    return table.FirstOrDefault((Func<T, bool>)lambdaExpression.Compile()); 
} 

你使用這樣的:

PAC xxx = GetByCodi<PAC>(_gam.PAC, codiPac, "CODI_PAC"); 

編輯1: 我根據註釋,這樣就可以在通過任意ID字段名稱改變了代碼

+0

此方法在所有ID以「CODI_ 「但我的DataBase中有一些表格不同於ID名稱。有一種方法可以知道表的ID,而且無論ID的名稱如何,這些方法都會自動生成。 – ramo2712 2011-05-04 16:43:33

+0

我更改了上面的代碼,以便它將id字段名稱作爲參數傳入。如果您對答案感到滿意,請接受它。 – 2011-05-04 20:00:59