.net 存储库模式以及域模型和实体框架之间的映射
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20944865/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Repository pattern and mapping between domain models and Entity Framework
提问by Dave New
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.
在大多数情况下,从数据实体构造域模型实例需要使用参数化的构造函数和方法(因为它很丰富)。它不像属性/字段匹配那么简单。AutoMapper 可用于相反的情况(映射到数据实体),但不能用于创建域模型。
Below is the core of my repository pattern.
下面是我的存储库模式的核心。
The EntityFrameworkRepositoryclass works with two generic types:
在EntityFrameworkRepository类的工作有两个泛型类型:
TDomainModel: The rich domain modelTEntityModel: The Entity Framework data entity
TDomainModel: 富域模型TEntityModel:实体框架数据实体
Two abstract methods are defined:
定义了两个抽象方法:
ToDataEntity(TDomainModel): To convert to data entities (forAdd()andUpdate()methods)ToDomainModel(TEntityModel): To construct domain models (for theFind()method).
ToDataEntity(TDomainModel): 转换为数据实体(forAdd()和Update()方法)ToDomainModel(TEntityModel): 构建领域模型(对于Find()方法)。
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 Companymight be composed of many Departments. If I want to eagerly load these from the CompanyRepositorywhen fetching a Companythen where would I define the mapping between a Departmentand a DepartmentDataEntity?
ACompany可能由许多Departments. 如果我想CompanyRepository在获取 a 时急切地加载它们Company,那么我将在哪里定义 aDepartment和 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.
我可以在 中提供更多的映射方法CompanyRepository,但这很快就会变得混乱。很快就会在整个系统中出现重复的映射方法。
What is a better approach to the above problem?
解决上述问题的更好方法是什么?
采纳答案by Ilya Palkin
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.
如果您使用 Entity Framework,它可以映射 Rich Domain Model 本身。
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 workand identity mapimplementation, etc. Modern ORMs know how to handle all these issues.
我一直在使用 NHibernate 并且知道在实体框架中您还可以指定从数据库表到 POCO 对象的映射规则。在实体框架实体上开发另一个抽象层是一项额外的工作。让 ORM 负责所有映射、状态跟踪、工作单元和身份映射实现等。现代 ORM 知道如何处理所有这些问题。
AutoMapper could be used for the opposite situation (mapping to data entities) but not when creating domain models.
AutoMapper 可用于相反的情况(映射到数据实体),但不能用于创建域模型。
You are completely right.
你是完全正确的。
Automapper is useful when one entity can be mapped into another without additional dependencies (e.g. Repositories, Services, ...).
当一个实体可以映射到另一个实体而无需附加依赖项(例如存储库、服务等)时,Automapper 很有用。
... where would I define the mapping between a
Departmentand aDepartmentDataEntity?
...我在哪里定义 a
Department和 a之间的映射DepartmentDataEntity?
I would put it into DepartmentRepositoryand add method IList<Department> FindByCompany(int companyId)in order to retreive company's departments.
我会把它放入DepartmentRepository并添加方法IList<Department> FindByCompany(int companyId)以检索公司的部门。
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?
我可以在 中提供更多的映射方法
CompanyRepository,但这很快就会变得混乱。很快就会在整个系统中出现重复的映射方法。解决上述问题的更好方法是什么?
If it is needed to get list of Departments for another entity, a new method should be added to DepartmentRepositoryand simply used where it is needed.
如果需要获取Department另一个实体的s列表,则应添加一个新方法DepartmentRepository并在需要时简单地使用它。
回答by Leo
Let's say you have the following data access object...
假设您有以下数据访问对象...
public class AssetDA
{
public HistoryLogEntry GetHistoryRecord(int id)
{
HistoryLogEntry record = new HistoryLogEntry();
using (IUnitOfWork uow = new NHUnitOfWork())
{
IReadOnlyRepository<HistoryLogEntry> repository = new NHRepository<HistoryLogEntry>(uow);
record = repository.Get(id);
}
return record;
}
}
which returns a history log entry data entity. This data entity is defined as follows...
它返回一个历史日志条目数据实体。该数据实体定义如下...
public class HistoryLogEntry : IEntity
{
public virtual int Id
{ get; set; }
public virtual int AssetID
{ get; set; }
public virtual DateTime Date
{ get; set; }
public virtual string Text
{ get; set; }
public virtual Guid UserID
{ get; set; }
public virtual IList<AssetHistoryDetail> Details { get; set; }
}
You can see that the property Detailsreferences another data entity AssetHistoryDetail. Now, in my project I need to map these data entities to Domain model objects which are used in my business logic. To do the mapping I have defined extension methods...I know it's an anti-pattern since it is language specific, but the good thing is that it isolate and breaks dependencies between each other...yeah, that's the beauty of it. So, the mapper is defined as follows...
您可以看到该属性Details引用了另一个数据实体AssetHistoryDetail。现在,在我的项目中,我需要将这些数据实体映射到我的业务逻辑中使用的域模型对象。为了进行映射,我定义了扩展方法……我知道这是一种反模式,因为它是特定于语言的,但好处是它隔离并打破了彼此之间的依赖关系……是的,这就是它的美妙之处。因此,映射器定义如下...
internal static class AssetPOMapper
{
internal static HistoryEntryPO FromDataObject(this HistoryLogEntry t)
{
return t == null ? null :
new HistoryEntryPO()
{
Id = t.Id,
AssetID = t.AssetID,
Date = t.Date,
Text = t.Text,
UserID = t.UserID,
Details = t.Details.Select(x=>x.FromDataObject()).ToList()
};
}
internal static AssetHistoryDetailPO FromDataObject(this AssetHistoryDetail t)
{
return t == null ? null :
new AssetHistoryDetailPO()
{
Id = t.Id,
ChangedDetail = t.ChangedDetail,
OldValue = t.OldValue,
NewValue = t.NewValue
};
}
}
and that's pretty much it. All dependencies are in one place. Then, when calling a data object from the business logic layer I'd let LINQdo the rest...
仅此而已。所有依赖项都在一个地方。然后,当从业务逻辑层调用数据对象时,我会让LINQ剩下的......
var da = new AssetDA();
var entry = da.GetHistoryRecord(1234);
var domainModelEntry = entry.FromDataObject();
Note that you can define the same to map Domain Model objects to Data Entities.
请注意,您可以定义相同的内容以将领域模型对象映射到数据实体。
回答by Ronald
With entity framework, across all layers IMHO, it is generally a bad idea to convert from entity models to other form of models (domain models, value objects, view models, etc.) and vice versa except only in the application layer because you will lose a lot of EF capabilities that you can only achieve through the entity objects, like loss of change tracking and loss of LINQ queryable.
对于实体框架,恕我直言,从实体模型转换为其他形式的模型(域模型、值对象、视图模型等)通常是一个坏主意,反之亦然,除非仅在应用程序层中,因为您将失去了许多只能通过实体对象实现的 EF 功能,例如更改跟踪丢失和 LINQ 可查询丢失。
It's better to do the mapping between your repository layer and the application layer. Keep the entity models in the repository layer.
最好在您的存储库层和应用程序层之间进行映射。将实体模型保留在存储库层中。
回答by Dave R
I like using custom-built Extension methods to do the mapping between Entity and Domain objects.
我喜欢使用定制的扩展方法来进行实体和域对象之间的映射。
- You can easily call extension methods for other entities when they are within a containing entity.
- You can easily deal with collections by creating IEnumerable<> extensions.
- 当其他实体在包含实体中时,您可以轻松调用它们的扩展方法。
- 您可以通过创建 IEnumerable<> 扩展轻松处理集合。
A simple example:
一个简单的例子:
public static class LevelTypeItemMapping
{
public static LevelTypeModel ToModel(this LevelTypeItem entity)
{
if (entity == null) return new LevelTypeModel();
return new LevelTypeModel
{
Id = entity.Id;
IsDataCaptureRequired = entity.IsDataCaptureRequired;
IsSetupRequired = entity.IsSetupRequired;
IsApprover = entity.IsApprover;
Name = entity.Name;
}
}
public static IEnumerable<LevelTypeModel> ToModel(this IEnumerable<LevelTypeItem> entities)
{
if (entities== null) return new List<LevelTypeModel>();
return (from e in entities
select e.ToModel());
}
}
...and you use them like this.....
......你像这样使用它们......
using (IUnitOfWork uow = new NHUnitOfWork())
{
IReadOnlyRepository<LevelTypeItem> repository = new NHRepository<LevelTypeItem>(uow);
record = repository.Get(id);
return record.ToModel();
records = repository.GetAll(); // Return a collection from the DB
return records.ToModel(); // Convert a collection of entities to a collection of models
}
Not perfect, but very easy to follow and very easy to reuse.
不完美,但很容易遵循并且很容易重用。
回答by Tsasken
Like previous posts have said. It's probably best to wait untill after the repositories to do actual mapping.. BUT I like working with auto-mapper. It provides a very easy way to map objects to other objects. For some separation of concerns, you can also define the mappings in a separate project. These mappings are also generic / type-based:
就像以前的帖子说的。最好等到存储库之后再进行实际映射。但我喜欢使用自动映射器。它提供了一种将对象映射到其他对象的非常简单的方法。对于某些关注点分离,您还可以在单独的项目中定义映射。这些映射也是通用的/基于类型的:
- You specify the base type in the mapping and define how it fills the destination type
- Where you need the mapping, you just call Mapper.Map(baseTypeObject, DestinationTypeObject)
- Automapper should handle the rest
- 您在映射中指定基本类型并定义它如何填充目标类型
- 在需要映射的地方,只需调用 Mapper.Map(baseTypeObject, DestinationTypeObject)
- Automapper 应该处理其余的
This could do the trick, if I understood your question correctly.
如果我正确理解您的问题,这可以解决问题。
回答by Volodymyr Bilyachat
I dont like to map manually so for mapping i am using http://valueinjecter.codeplex.com/
我不喜欢手动映射所以映射我使用http://valueinjecter.codeplex.com/

