Legion
Legion

Reputation: 3427

Where do I put my mapping logic?

I have a domain model, a repository and entity framework. I don't want my domain tied to EF or the persistence layer in general.

So I created a repository to keep things like db.Users.Where(u => u.Team == "MyTeam") out of my domain.

After implementing the generic repository pattern if I want a list of users on a particular team I use UserRepository.GetUsersByTeam("MyTeam").

The problem is my UserRepository is returning IEnumerable<EntityFrameworkUser>, instead of IEnumerable<DomainUser>, and in order to return IEnumerable<DomainUser> I need to map DomainUser to EntityFrameworkUser somewhere.

So where specifically do you map from the EntityFrameworkUser class to the DomainUser class?

Should the repository encapsulate the mapping logic in addition to the query logic?

If I want a collection of domain user objects what does the call stack look like for UserRepository.GetUsersByTeam("MyTeam") look like?

Searching has only found me general responses that usually quote Martin Fowler. I need a concrete example to refer to.

Upvotes: 2

Views: 1587

Answers (3)

Andrei Mihalciuc
Andrei Mihalciuc

Reputation: 2258

If you want to keep domain object separately - keep them separately. If you repository returns objects from persistent layer, then it opens door for over-posting issues (it especially dangerous when front-end uses the same objects). I would move mapping logic into another class and use it in your repositories.

Automapper is very popular library for mapping different object, for example Domain object to DTO and vise versa. You can inject Automapper into your repositories and use it to map IEnumerable<EntityFrameworkUser> to IEnumerable<DomainUser>. First register mapping

Mapper.CreateMap<EntityFrameworkUser, DomainUser>();

Then call it from your repository

return Mapper.Map<IEnumerable<EntityFrameworkUser>, IEnumerable<DomainUser>>(users);

Upvotes: 1

Tony Vitabile
Tony Vitabile

Reputation: 8594

If the purpose of the method in question is simply to always return all of the members of the specified team, and you're never going to apply additional clauses to the result, you could change the return type of the UserRepostory.GetUsersByTeam() method from the EF DbSet<User> type to List<User>, then change the return statement to return db.Users.Where(u => u.Team == "MyTeam").ToList().

You'll no longer get the EF objects out of the repository level.

Upvotes: -1

David
David

Reputation: 218827

The problem is my UserRepository is returning an entity framework User DbSet

That shouldn't be the return type, because that would introduce coupling. You can still return that type, but it should be polymorphically interpreted as a different type.

So while you may be doing something like this in your repository:

return db.Users;

The return type shouldn't be that implementing type (DbSet<User>?), but something more generic:

public IQueryable<User> GetUsers()
{
    return db.Users;
}

The "EF objects" are being used throughout the domain, but the domain doesn't know or care about that. The domain sees it as a queryable collection of User models.

Upvotes: 2

Related Questions