如何在EF,Autofac和通用数据存储库中使用DTO?

时间:2014-02-07 17:06:58

标签: c# repository-pattern dto unit-of-work

如何将DTO与EF,Autofac和通用数据存储库一起使用?

我正在设置一个新项目并配置了我的DI / IoC(Autofac),使用通用存储库通过EF进行数据访问,并创建了一个OData服务端点ContentTypesController。< / p>

这是控制器的顶部:

public class ContentTypesController : ODataController, IContentTypesController
{

    // add repository reference
    private readonly IRepository<ContentType> _repository;

    private ProjectV001Context _db = new ProjectV001Context();

    /// <summary>
    /// Constructor - setup for DI
    /// </summary>
    /// <param name="contentTypeRepository"></param>
    public ContentTypesController(IRepository<ContentType> repository)
    {
        _repository = repository;
    }

    // GET odata/ContentTypes
     [Queryable]
    public Task<IQueryable<ContentType>> Get(ODataQueryOptions<ContentType> options)
    {
        // mock
        var userId = 102;
        //var unitOfWork = new Repository.UnitOfWork(_db);   <-- removed from the original question
        var result = _repository.Query()
            .Filter(u => u.UserId == userId)
            .GetAsync();

        return result;
    }

ContentType是Project.DAL.Data.Models中的EF类,它包含客户端不需要查看/使用的字段 - 即。用户身份。在插入或更新方法时,将以实际方式设置此字段的值。

我的DTO位于Project.Core.ContentTypes。

1)我是否正确使用了工作单元模式?

2)我希望我的方法返回DTO,而不是实际实体对象的所有字段。我该如何设置?

- 更新 -

在之前的项目(和不同的存储库)中,我按如下方式实现了UoW:

public class ContentTypesController:ODataController     {         private ProjectDbContext _db = new ProjectDbContext();

public IEnumerable<ContentType> Get(ODataQueryOptions<ContentType> options)
{
    var unitOfWork = new Project.Repository.UnitOfWork(_db);

    var contentTypes = options.ApplyTo(unitOfWork.Repository<ContentType>().Queryable
        .OrderBy(c => c.Description))
        .Cast<ContentType>().ToList();

    unitOfWork.Save();      // includes Dispose()

    return contentTypes;
}

1 个答案:

答案 0 :(得分:2)

嗯,你实际上并没有使用UnitOfWork模式;只是通用的存储库模式。至于返回DTO,请查看Factory模式(我使用AutoMapper)。您可以创建您的dtos并使用automapper作为工厂来获取您的实体并转换为dtos或您的dtos并转换为实体。配置AutoMapper非常简单,如下所示:

Mapper.CreateMap<ContentType, ContentTypeDto>();

实际上将ContentType映射到ContentTypeDto(假设您的属性名称匹配):

var dto = Mapper.Map<ContentType, ContentTypeDto>(contentTypeEntity);

至于工作单元:除非你计划在某个时候更换你的ORM,否则没有使用它。但如果你真的想要它,那很简单:

public class UnitOfWork : IUnitOfWork
{
    private readonly IDbContext _context;
    private readonly Dictionary<Type, object> _repos;

    public IRepository<T> GetRepository<T>() {
        if (_repos.ContainsKey(typeof (T)))
            return _repos[typeof (T)] as IRepository<T>;

        var repo = new Repository(_context);
        _repos.Add(typeof (T), repo);

        return repo;
    }

    public int SaveChanges() {
        return _context.SaveChanges();
    }

    dispose stuff - make sure to dispose your context
}

IUnitOfWork实现了IDisposable并定义了GetRepository()和SaveChanges()。

您还必须创建IDbContext,它只定义Set,SaveChanges(),并实现IDisposable。

然后,您可以将IUnitOfWork注入控制器并使用GetRepository()为您的控制器检索正确的存储库。这样,所有存储库共享1个单独的上下文。

Implement a Generic Repository and a Unit of Work Class example is about half way down this page. Only difference is their UnitOfWork is not generic but I showed you that above.

编辑:我刚刚注意到你从你的存储库中获得了一个UnitOfWork:

var unitOfWork = new Repository.UnitOfWork(_db);
var result = unitOfWork.Repository<ContentType>()...

我不确定这里发生了什么。你的UnitOfWork应该放弃你的存储库,但看起来你的存储库给你的工作单元,然后你的UnitOfWork给你一个存储库?你介意分享你的存储库吗?我相信要正确实现UnitOfWork,您需要编辑您的存储库。