c# - 通过存储库将数据库实体映射到域实体 - 静态属性或单独的服务?

标签 c# asp.net-mvc entity-framework repository domain-driven-design

我正在开发一个应用程序,其中我的数据库模式与我的域模型不匹配,并且对数据库模式的修改不在我的控制之下。因此,我最终在我的存储库调用中做了很多映射,并且我有许多具体的存储库来处理与数据库的映射(首先使用实体​​框架数据库)。我正在寻找的是一种基于域实体对象类型调用我的存储库的优雅方法。到目前为止,领域模型本身仍然非常贫乏,因为我们仍在定义业务规则的过程中。

我在别处看到过一个示例(不记得链接),其中存储库调用是通过静态属性通过域实体传递的,但我不知道这是否会出现线程问题或是否违反任何域模型原则,特别是如果我们决定在未来实现 DI/IoC。

这是我目前所拥有的示例。为了简洁起见,我简化了对数据库的映射调用,因为实际应用中的映射更为复杂。

存储库示例:

public interface IRepository<T>
{
    T GetById(int id);
    void Save(T entity);
}

public abstract class RepositoryFactory<T> : IRepository<T>
{
    protected MyDbContext db;
    protected int userId;

    protected RepositoryFactory()
    {
        this.db = new MyDbContext();
        this.userId = WebSecurity.GetCurrentUser().UserId;
    }

    public abstract T GetById(int id);
    public abstract void Save(T entity);
}

public class CustomerRepository : RepositoryFactory<Customer>
{
    public override void Save(Customer customer)
    {
        var entity = db.customers.FirstOrDefault(p => p.customerid == customer.Id && p.users.userid == userId);

        if (entity == null) return;  // TODO: Add error trapping

        // Mapping (lots of reshaping happening here)
        entity.customername = customer.Name;
        entity.customeraddress = customer.Address;
        // ...

        // Save changes to DB
        db.Entry(entity).State = EntityState.Modified;
        db.SaveChanges();
    }

    public override Customer GetById(int id)
    {
        var entity = db.customers.FirstOrDefault(p => p.customerid == id && p.users.userid == userId);
        if (entity == null) return null;  // TODO: Add error trapping
        return new Customer
        {
            Name = entity.customername,
            Address = entity.customeraddress,
            // ...
        };
    }
}

域实体示例:

public class Entity { public int Id { get; set; } }

public class Customer : Entity
{
    public string Name { get; set; }
    public string Address { get; set; }

    // Does this violate any domain principles?
    public static IRepository<Customer> Repository
    {
        get { return new CustomerRepository(); }
    }
}

使用此代码,我可以从我的 Controller 中执行以下操作:

Customer customer = Customer.Repository.GetById(id);

代替:

IRepository<Customer> repo = new CustomerRepository();
Customer customer = repo.GetById(id);

对于我的问题,这似乎是一个非常优雅的解决方案,而且它还使我无需在我的 Controller (MVC) 中包含 Repository 命名空间。如果这听起来很有趣并且有更好的方法来处理这个问题,我很乐意学习。我唯一能想到的另一件事是创建一个单独的 crud 服务来处理我的存储库调用,但我想为此我需要一个字典或哈希表来将我的具体存储库映射到我的域模型对象,这似乎会成为维护的噩梦。

最佳答案

我建议使用控制反转(依赖注入(inject))容器并将您的存储库注入(inject)您的 Controller 或任何地方。这样你就可以像这样使用它们:

public class HomeController : Controller
{
    private readonly IRepository<Customer> _customerRepository;

    public HomeController(IRepository<Customer> customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public ActionResult Index(int id)
    {
        var customer = _customerRepository.GetById(id)

        return View(customer);
    }
}

这样,如果您需要替换 CustomerRepository 类,或者需要多个版本(比如 CustomerRepositoryEntityFramework 或 CustomerRepositoryNHibernate),您只需替换一个继承自 IRepository 的新类,您的 Controller 代码仍将继续工作而无需更改。

我建议使用 CaSTLe Windsor、Ninject 或许多其他 IoC 容器之一。

此外,您通常希望将域实体保留为 poco(普通旧 CLR 对象)。这意味着将所有内容从您的实体中分离出来,包括验证、业务规则等,并且只拥有它的属性。这使您可以更轻松地通过管道传递域实体,特别是因为您处于开发的早期阶段。这将为您在未来提供最大的灵 active 。

关于c# - 通过存储库将数据库实体映射到域实体 - 静态属性或单独的服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19983669/

相关文章:

c# - Gridview 中的 TextBox 返回 null 或 'System.Web.UI.WebControls.TextBox'

c# - 我想使用基类,但我不想调用应用程序了解它,我该怎么做? C#

c# - WebClient.DownloadProgressChanged 永远不会被调用

c# - Entity Framework : Any(. .)-从 EF5 升级到 EF6 后使用 == 过滤匹配 NULL

c# - 有没有 "standard MVC"混合 Javascript 和 Razor 的方法?

c# - ASP.NET MVC Razor 语法 : Is it an issue for razor to interpret @if(@Model

c# - 如何将搜索引擎添加到 GeckoFx 网络浏览器?

sql-server - 跨数据库查询。如何正确使用跨数据库功能?

c# - EntityFramework 的 AddOrUpdate 导致外键更新不正确

svn - 强制 subversion 不合并特定文件