2016-09-20 50 views
2

我喜歡使用擴展方法從我的實體模型投影到我的視圖模型中。這意味着我不會超過/低於我的模型獲取,它使代碼更好和可讀。有意義的是,有時候這些預測可能包含嵌套模型,我想在這些子預測中得到重用。使用擴展方法在EF中投影單個實體

我希望能夠像做了以下內容:實際投影

ctx.People.FiltersAndThings().ToViewModels();//the project my DB Models into view models 

擴展方法

public static IQueryable<PersonModel> ToViewModels(this IQueryable<Person> entities) 
{ 
    return entities.Select(x => new PersonModel { 
     Me = x.Me.ToViewModel(), //this method cannot be translated into a store expression 
     Friends = x.Friends.AsQueryable().ToViewModels() //works fine with some magic (tm) 
    }); 
} 

public static IQueryable<ProfileModel> ToViewModels(this IQueryable<Profile> entities) 
{ 
    return entities.Select(x => new ProfileModel { Name = x.Name }); 
} 


public static ProfileModel ToViewModel(this Profile entity) 
{ 
    return new ProfileModel { Name = entity.Name }; 
} 

當使用可查詢(例如Friends = x.Friends.AsQueryable().ToViewModels()),我們可以使用一些魔法變平這對一個表達式(見https://stackoverflow.com/a/10726256/1070291,通過@LordTerabyte答案)但是,當我們用新的條款做一個任務(如Me = new ProfileModel { Name = x.Me.Name })它不是一種表達,所以如果我們捆綁這下擴展方法(例如Me = x.Me.ToViewModel())我們不能把這個變成一個表達式。

如何在EF場景下分配給新的對象的工作?

有沒有辦法通過擴展方法轉換爲新對象?

完整的示例代碼在這裏:https://github.com/lukemcgregor/ExtensionMethodProjection

編輯:

我現在有一個博客帖子(Composable Repositories - Nesting Extensions)和nuget package,以幫助在LINQ

+0

它是否適用於你當前的代碼? –

+0

'我= x.Me.ToViewModel()'不工作,如果你想休息的演示應用程序的工作,我可以張貼到GH –

+0

其實這將有助於看到你'Person'模型和'PersonModel',而不是完整的代碼,但相關的部分。 –

回答

2

嵌套擴展方法看看this answer。它做了你想要的非常類似的事情。基本上你會定義轉製爲表達式樹,e.g:

public static Expression<Func<Profile, ProfileModel>> ToProfileViewModel() 
{ 
    return entity => new ProfileModel { Name = entity.Name }; 
} 

然後做到這一點(例如ExpressionsHelper.ToProfileViewModel()AsQuote()(P))的調用。

如果你願意,你可以修改訪問者,以允許更好的語法。沿着線的東西:

[ReplacementInExpressionTrees(MethodName=nameof(ExpressionsHelper.ToProfileViewModel))] 
public static ProfileModel ToViewModel(this Profile profile) 
{ 
    // this implementation is only here, so that if you call the method in a non expression tree, it will still work 
    return ExpressionsHelper.ToProfileViewModel().Compile()(profile); // tip: cache the compiled func! 

現在,你需要創建一個訪客,來檢查所有方法調用,當找到一個方法與此屬性,它改變ExpressionsHelper.ToProfileViewModel()整個呼叫AsQuote()。 (配置文件)。這是對你的練習:) }

+0

你也可以直接將這樣的結構轉換爲想要的目標表達式 – MBoros

+0

這看起來很棒,你提到'ReplacementInExpressionTreesAttribute',這會是什麼樣子?我認爲這是我需要寫的東西?它看起來應該用樹中使用的表達式替換方法調用。這正是什麼即時通訊:) –

+0

哦,我得到你你說我應該寫這個,生病了去... –