Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
271 views
in Technique[技术] by (71.8m points)

.net - Repository pattern and mapping between domain models and Entity Framework

My repositories deal with and provide persistence for a rich domain model. I do not want to expose the anemic, Entity Framework data entity to my business layers, so I need some way of mapping between them.

In most cases, constructing a domain model instance from a data entity requires the use of parameterised constructors and methods (since it is rich). It is not as simple as a property/field match. AutoMapper could be used for the opposite situation (mapping to data entities) but not when creating domain models.

Below is the core of my repository pattern.

The EntityFrameworkRepository class works with two generic types:

  • TDomainModel: The rich domain model
  • TEntityModel: The Entity Framework data entity

Two abstract methods are defined:

  • ToDataEntity(TDomainModel): To convert to data entities (for Add() and Update() methods)
  • ToDomainModel(TEntityModel): To construct domain models (for the Find() method).

Concrete implementations of these methods would define the mapping required for the repository in question.

public interface IRepository<T> where T : DomainModel
{
    T Find(int id);
    void Add(T item);
    void Update(T item);
}

public abstract class EntityFrameworkRepository<TDomainModel, TEntityModel> : IRepository<TDomainModel>
    where TDomainModel : DomainModel
    where TEntityModel : EntityModel
{
    public EntityFrameworkRepository(IUnitOfWork unitOfWork)
    {
        // ...
    }

    public virtual TDomainModel Find(int id)
    {
        var entity = context.Set<TEntityModel>().Find(id);

        return ToDomainModel(entity);
    }

    public virtual void Add(TDomainModel item)
    {
        context.Set<TEntityModel>().Add(ToDataEntity(item));
    }

    public virtual void Update(TDomainModel item)
    {
        var entity = ToDataEntity(item);

        DbEntityEntry dbEntityEntry = context.Entry<TEntityModel>(entity);

        if (dbEntityEntry.State == EntityState.Detached)
        {
            context.Set<TEntityModel>().Attach(entity);

            dbEntityEntry.State = EntityState.Modified;
        }
    }

    protected abstract TEntityModel ToDataEntity(TDomainModel domainModel);
    protected abstract TDomainModel ToDomainModel(TEntityModel dataEntity);
}

Here is a basic example of a repository implementation:

public interface ICompanyRepository : IRepository<Company>
{
    // Any specific methods could be included here
}

public class CompanyRepository : EntityFrameworkRepository<Company, CompanyTableEntity>, ICompanyRepository
{
    protected CompanyTableEntity ToDataEntity(Company domainModel)
    {
        return new CompanyTable()
        {
            Name = domainModel.Name,
            City = domainModel.City
            IsActive = domainModel.IsActive
        };
    }

    protected Company ToDomainModel(CompanyTableEntity dataEntity) 
    {
        return new Company(dataEntity.Name, dataEntity.IsActive)
        {
            City = dataEntity.City
        }
    }
}

Problem:

A Company might be composed of many Departments. If I want to eagerly load these from the CompanyRepository when fetching a Company then where would I define the mapping between a Department and a DepartmentDataEntity?

I could provide more mapping methods in the CompanyRepository, but this will soon get messy. There would soon be duplicated mapping methods across the system.

What is a better approach to the above problem?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

My repositories deal with and provide persistence for a rich domain model. I do not want to expose the anemic, Entity Framework data entity to my business layers, so I need some way of mapping between them.

If you you use Entity Framework, it can map Rich Domain Model itself.

I've answered the similar question "Advice on mapping of entities to domain objects" recently.

I've been using NHibernate and know that in Entity Framework you can also specify mapping rules from DB tables to your POCO objects. It is an extra effort to develop another abstraction layer over Entity Framework entities. Let the ORM be responsible for all of the mappings, state tracking, unit of work and identity map implementation, etc. Modern ORMs know how to handle all these issues.

AutoMapper could be used for the opposite situation (mapping to data entities) but not when creating domain models.

You are completely right.

Automapper is useful when one entity can be mapped into another without additional dependencies (e.g. Repositories, Services, ...).

... where would I define the mapping between a Department and a DepartmentDataEntity?

I would put it into DepartmentRepository and add method IList<Department> FindByCompany(int companyId) in order to retreive company's departments.

I could provide more mapping methods in the CompanyRepository, but this will soon get messy. There would soon be duplicated mapping methods across the system.

What is a better approach to the above problem?

If it is needed to get list of Departments for another entity, a new method should be added to DepartmentRepository and simply used where it is needed.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...