0

I have a DAL layer that contains an EF Dbcontext and entities. I have a service that contains a method where I want to do a simple Select that comes from the logic layer.

Layer: Logic=>DalService=>DbContext.DbSet.Select(something)

DAL does not know about any DTO models. Logic layer does not know about any Entities.

I'm basically trying to convert: Func<T, dynamic> selector to Func<TEntity, dynamic> selector which I can basically use on a DbSet<TEntity>.

Thanks

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
MrH40XX
  • 35
  • 1
  • 9
  • 1
    FWIW, I'd consider your architecture to be something of an anti-pattern, and I presume you're doing this to separate concerns or make unit testing easier. Your "Logic" layer should access the DbContext directly, to reduce the need for complex middleware such as what you're looking for. This layer should then map any results to DTO models if necessary. – Paul Suart Sep 27 '17 at 10:55
  • 1
    Maybe it is `Expression>` instead of `Func`? – ASpirin Sep 27 '17 at 10:59
  • 1
    See this question for a similar requirement: https://stackoverflow.com/questions/2797261/mutating-the-expression-tree-of-a-predicate-to-target-another-type – Paul Suart Sep 27 '17 at 11:02
  • Yes; Expression> to Expression> – MrH40XX Sep 27 '17 at 11:02

1 Answers1

2

AutoMapper has a feature called Expression Translation that can do the work of translating from your logic layer queries to your DAL queries.

First you need to setup a mapping from TEntity (your entity type from your DAL) to T (your DTO from your logic layer):

Mapper.Initialize(cfg => cfg.CreateMap<TEntity, T>());

Then when your DAL is given a query expression from the logic layer like this example:

Expression<Func<DTO, dynamic>> logicExpression = (dto) => new { dto.SomeProperty }; 

It can translate it like so:

var dalExpression = Mapper.Map<Expression<Func<TEntity, dynamic>>>(logicExpression);

Finally to be invoked against your EF context:

var results = context.SomeSet.Select(dalExpression).ToList();
urig
  • 16,016
  • 26
  • 115
  • 184
  • Yes, correct. However the dynamic means I'm trying to: method: dynamic GetMyModelById(long id, Func f) { } Usage: GetMyModelById(1, f => new { f.code, f.name }) – MrH40XX Sep 27 '17 at 10:50
  • 1
    `AutoMapper` maps **data**, it does not map an expression or lambda. – Maarten Sep 27 '17 at 10:51
  • 1
    I'm not looking for automapper. I'm looking for dynamic mapping. I want an anonymous object that I define on the logic layer. I want to get the entity but not all fields. Since my entity contains a lot of fields I just want to select a few. I don't feel like making 100 models and 100 different methods where only the selected fields are different. – MrH40XX Sep 27 '17 at 10:55
  • Now I get what you're aiming for. You're given a selector based on one type and need to translate it to the same selection on a different type. – urig Sep 27 '17 at 11:08
  • 1
    @Maarten Actually it does - [Expression Translation](https://github.com/AutoMapper/AutoMapper/wiki/Expression-Translation-(UseAsDataSource)) – Ivan Stoev Sep 27 '17 at 11:10
  • The AutoMapper works with models and not on the fly anonymous objects does it? I'm using AutoMapper projection now but it doesn't do the trick because it always maps the full model OR I need to create different mapperconfigs for each select. – MrH40XX Sep 27 '17 at 11:28
  • 1
    Maybe AutoMapper's Expression Translation can do the trick? https://github.com/AutoMapper/AutoMapper/wiki/Expression-Translation-(UseAsDataSource)? I see @ivan-stoev found this before me so I leave it to him to promote to a full answer :) – urig Sep 27 '17 at 11:28
  • 1
    @urig Thanks, but I'm not planning to. Please feel free to update your answer and I'll be happy to vote it up :) – Ivan Stoev Sep 27 '17 at 11:32