2016-11-24 68 views
0

我的問題由下面的代碼示例說明。 我如何在其他地方放置部分lambda?從lambda表達式到多重LINQ表達式的拆分邏輯

如何從我的'GetGurus()'方法調用'Foo'? 我希望LINQ將它翻譯爲1條語句。

public enum GuruLevel 
{ 
    NotSet, 
    Goku, 
    SuperSayan 
} 

private IEnumerable<PersonInfo> GetGurus() 
{ 
    using (var context = new CRMContext()) 
    { 
     var persons = context.Person 
      .Where(p => p.Experience > 10) 
      .OrderBy(p => p.DateOfBirth) 
      .Select(p => new PersonInfo()) 
      { 
       StackOverFlowName = p.StackOverFlowName, 
       Experience = p.Experience, 
       GuruStatus = Foo //(p.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku 
      } 
     return persons.ToList(); 
    } 
} 

public static System.Linq.Expressions.Expression<Func<Person, GuruLevel>> Foo 
{ 
    get 
    { 
     return bar => (bar.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku; 
    } 
} 
+0

http://stackoverflow.com/questions/27324641/reusable-calculations-for-linq-projections-in-entity-framework-code-first – jeroenh

+0

我讀你的鏈接,看來這正是我需要。雖然看起來相當複雜: –

+1

太糟糕了,您沒有發佈答案,因爲您給出了最好的答案!我安裝了[DelegateDecompiler](https://www.nuget.org/packages/DelegateDecompiler/)。 –

回答

0

改變這個;

public static Func<Person, GuruLevel> Foo 
{ 
    get 
    { 
     return bar => (bar.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku; 
    } 
} 

然後;

private IEnumerable<PersonInfo> GetGurus() 
{ 
    using (var context = new CRMContext()) 
    { 
     var persons = context.Person 
      .Where(p => p.Experience > 10) 
      .OrderBy(p => p.DateOfBirth) 
      .Select(p => new PersonInfo()) 
      { 
       StackOverFlowName = p.StackOverFlowName, 
       Experience = p.Experience, 
       GuruStatus = Foo(p) 
      } 
     return persons.ToList(); 
    } 
} 

只是一個說明;這是一個奇怪的做法。你可以讓Foo成爲一個正常的功能,它會很好;

public GuruLevel Foo(Person bar) 
{ 
    return bar.Experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku; 
} 
... 
GuruStatus = Foo(p) 
+0

謝謝你的嘗試,但是這會導致:'LINQ表達式節點類型'Invoke'不支持LINQ to Entities。'' –

+0

@Tony_KiloPapaMikeGolf答案在linq-你沒有指定你在EF – jeroenh

+0

的環境下工作沒有注意,我不知道它是EF,也許我的編輯會工作'因爲它是一個標準的樂趣ction。不確定。我不使用EF – bixarrio

1

這個邏輯是PersonInfo類的職責。此代碼通常放置在構造函數或工廠類中,並完全符合單責任原則。

class PersonInfo 
{ 
    public string StackOverFlowName { get; set; } 
    public int Experience { get; set; } 
    public GuruLevel GuruStatus { get; set; } 

    public void PersonInfo(Person p) 
    { 
     StackOverFlowName = p.StackOverFlowName; 
     Experience = p.Experience; 
     GuruStatus = p.Experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku; 
    } 
} 

然後改變你的服務的方法:

private IEnumerable<PersonInfo> GetGurus() 
{ 
    using (var context = new CRMContext()) 
    { 
     var persons = context.Person 
      .Where(p => p.Experience > 10) 
      .OrderBy(p => p.DateOfBirth) 
      .ToList() 
      .Select(p => new PersonInfo(p)) 
     return persons.ToList(); 
    } 
} 

或移動負責工廠:

public class PersonInfoFactory 
{ 
    public PersonInfo Create(Person person) 
    { 
     return new PersonInfo 
     { 
      StackOverFlowName = p.StackOverFlowName, 
      Experience = p.Experience, 
      GuruStatus = ExperienceBasedStatus(p.Experience) 
     }; 
    } 

    private GuruLevel ExperienceBasedStatus(int experience) => experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku; 
} 
+0

如果'CrmContext'是EF6,這將在查詢翻譯期間在運行時崩潰。不支持帶參數的構造函數。 – Impworks

+0

我喜歡它,但問題是關於拆分lambda。仍然+1 – bixarrio

+0

@Impworks的確如此,他可能會在初始化之前執行此查詢。 –

1

這不是你的問題直接回答,但它涉及到你的理由問。

我認爲,你正在使用某種數據庫,所以你不能使用常規方法,因爲它們不會被數據庫的上下文知道。

例如,您實際上可以執行使用數據執行某些操作的私有方法,但不能使用自定義類型或類。在你的例子中,'GuruLevel'不會被數據庫識別。

我建議不要嘗試在數據庫一側進行轉換。而是以數據庫格式檢索所需的所有數據,並在應用程序端進行轉換。

using (var context = new CRMContext()) 
{ 
    var persons = context.Person 
     .Where(p => p.Experience > 10) 
     .OrderBy(p => p.DateOfBirth) 
     .Select(p => new {p.StackOverFlowName, p.Experience }) //or whole object, or other fields if needed 
     .ToList() //executes query, all following code will be in a context of application not DB 
     .Select(p => new PersonInfo()) 
     { 
      StackOverFlowName = p.StackOverFlowName, 
      Experience = p.Experience, 
      GuruStatus = GetGuruStatus(p.Experience) 
     } 
    return persons.ToList(); 
} 

private GuruLevel GetGuruLevel(int exp) 
{ 
    return exp > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku 
}