从Mongo读取数据时发送IRepository模型依赖项

时间:2018-11-05 21:08:03

标签: c# mongodb dependency-injection domain-driven-design autofac

在我的应用中,我使用Autofac ContainerBuilder来注册我的存储库...

我还有一个CustomerModel类,它代表MongoDB集合。它还对其他域模型具有IRepository依赖项:

public class CustomerModel
{
    private readonly IRepository<OrderModel> _ordeRepository;

    public CustomerModel(IRepository<OrderModel> ordeRepository)
    {
        _ordeRepository = ordeRepository;
    }

    [BsonId]
    public ObjectId Id;

    public string Email;

    ...

    public List<OrderModel> Orders
    {
        get { return _ordeRepository.List(x => x.CustomerId == Id); }
    }
}

从Mongo读取数据时如何注入IRepository <>依赖项?

public interface IRepository<TEntity>
{
    IList<TEntity> List(Expression<Func<TEntity, bool>> expression);
}

public class MongoRepository<TEntity> : IRepository<TEntity>
{
    public IList<TEntity> List(Expression<Func<TEntity, bool>> expression)
    {
        IMongoCollection<TEntity> collection = ...;
        return collection.FindSync(expression).ToList();
    }
}

1 个答案:

答案 0 :(得分:2)

您不应将实现直接与您的媒体资源相关联。原因是,实体代表您的数据,但实体并不关心项目的存储或创建方式。只是您的业务对象的表示。

另一个问题是,按照Martin Fowler和Evans的定义,您在遵循域驱动的设计中违反了更常见的做法。最大的违法行为之一是您在属性中强加了逻辑,如果您调用该属性,则会自动访问数据库。

如C#深入作者所述:

  

对于您编写的每种类型,都应考虑其与   世界其他地方(包括同一程序集中的类)。这个   是它对所提供内容的描述,即其外向角色。   实施不应该是该描述的一部分,仅此而已   绝对必须如此。 (这就是为什么我更喜欢组合而不是继承,   选择有意义的地方-继承通常会暴露或限制   可能的实现。)

     

属性传达了“我将为   您,或者接受您的价值。”这不是实现概念,   这是一个界面概念。另一方面,一个领域进行交流   实现-它说“此类型表示此值   非常具体的方式”。没有封装,这是裸存储   格式。这是字段不属于接口的一部分原因-   他们不属于那里,因为他们谈论如何取得成就   而不是实现的目标。

     

我完全同意,很多时候实际上都可以使用字段   在应用程序的生存期内没有任何问题。只是不清楚   事先是那个时代,仍然违反了设计   不公开实施的原则。

在遵循设计原则的同时处理实现可能更适合以下方法和/或体系结构样式。请记住,图案不是千篇一律。他们出于特定原因解决特定问题,引入了自身的复杂性和问题。您必须根据您的应用程序权衡解决方案的优点。

// Repositories:
public interface ICustomerRepository : IDisposable
{
     IEnumerable<CustomerModel> RetrieveAllCustomers();

     CustomerModel RetrieveCustomerWithOrders(int id);
}

// Context:
public class CustomerContext : ICustomerRepository
{
     private bool disposed = false;
     private readonly IDbConnection dbConnection;

     public CustomerContext(IConfiguration configuration) => dbConnection = configuration.GetConnectionString("dbConnection");

     public IEnumerable<CustomerModel> RetrieveAllCustomers() => dbConnection.Query<CustomerModel>(query);

     public CustomerModel RetrieveCustomerWithOrders(int id) => dbConnection.Query<CustomerModel, OrderModel, CustomerModel>(query, (customer, order) =>
     {
          customer.Orders = order;
          return customer;
     }, new { CustomerId = id });

     public virtual bool Dispose(bool disposing)
     {
         if(!disposed)
         {
              if(disposing)
                  dbConnection.Dispose();

              disposed = true;
         }
     }

     public void Dispose() 
     {
          Dispose(true);
          GC.SuppressFinalize(this);
     }

     ~CustomerContext() => Dispose(true);     
}

// Factory:
public class CustomerFactory : ICustomerFactory
{
     private readonly IConfiguration configuration;

     public CustomerFactory(IConfiguration configuration) => this.configuration = configuration;

     public ICustomerRepository InstantiateCustomer() => new CustomerContext(configuration);
}

public interface ICustomerFactory
{
     ICustomerRepository InstantiateCustomer();
}

因此,我们已经创建了一些抽象,已经构建了容器,并且已经有了具有适当实现的明确合同。因此,如果有人现在要使用您所构建的内容,它将类似于以下内容:

public class CustomerService
{
     private readonly ICustomerFactory customerFactory;
     private readonly IConfiguration configuration;

     public CustomerService(ICustomerFactory customerFactory, IConfiguration configuration)
     {
          this.customerFactory = customerFactory;
          this.configuration = configuration;
     }

     public IEnumerable<CustomerModel> GetAllCustomers()
     {
         using(var customerContext = customerFactory.InstantiateCustomer(configuration))
              return customerContext.RetrieveAllCustomers();
     }

     public CustomerModel GetCustomerOrders(CustomerModel customer)
     {
          using(var customerContext = customerFactory.InstantiateCustomer(configuration))
              return customerContext.RetrieveCustomerWithOrders(customer.Id);
     }
}

因此,当它们与您的服务实现交互时,将创建清晰度,但也将允许清晰,简洁和富于表现力的代码流。实现者可以清楚地看到服务实现中发生了什么,但是完全不了解数据实现是如何发生的。

我没有添加任何错误处理或null检查,但希望能对您有所帮助。