2016-09-20 8 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, ответ by @LordTerabyte). Но когда мы выполняем назначение с новым предложением (например, Me = new ProfileModel { Name = x.Me.Name }), это не выражение, поэтому, если мы свяжем это под методом расширения (например, Me = x.Me.ToViewModel()), мы не можем сгладить это выражение.

Как присвоение нового объекта работает под сценами в EF?

Есть ли способ сделать переход на новый объект с помощью метода расширения?

Полный демо-код здесь: https://github.com/lukemcgregor/ExtensionMethodProjection

Edit:

теперь у меня есть сообщение в блоге (Composable Repositories - Nesting Extensions) и nuget package, чтобы помочь с гнездовыми методами расширения в LINQ

+0

Работает ли он с вашим текущим кодом? –

+0

'Me = x.Me.ToViewModel()' не работает, если вы хотите, чтобы демонстрационное приложение остального работало, я могу отправить сообщение в GH –

+0

Фактически это поможет увидеть вашу модель «Person» и «PersonModel», а не полный код, но соответствующие части. –

ответ

2

Взгляни this answer. Это очень похоже на то, что вы хотите. В основном вы должны определить ваше преобразование как дерево выражений, например:

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

А потом делать вызовы этого (например, ExpressionsHelper.ToProfileViewModel() AsQuote() (р).).

Если вы предпочитаете, вы можете изменить посетителей, чтобы обеспечить более удобный синтаксис. Что-то вдоль линий:

[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

О, я вам говорю, вы говорите, что я должен это написать, больно идти ... –