我想知道我应该如何对我的存储库进行分组?就像我在 asp.net mvc 和我的书中看到的示例一样,它们基本上每个数据库表使用一个存储库。但这似乎有很多存储库导致您稍后不得不调用许多存储库来进行模拟和其他东西。
所以我猜我应该将它们分组。但是我不确定如何对它们进行分组。
现在我创建了一个注册存储库来处理我所有的注册内容。但是,在我有 3 个存储库来执行此操作之前,我需要更新 4 个表。
例如,其中一个表是许可证表。当他们注册时,我查看他们的密钥并检查它是否存在于数据库中。现在,如果我需要在注册以外的其他地方检查此许可证密钥或该表中的其他内容,会发生什么情况?
一个地方可能是登录(检查密钥是否未过期)。
那么在这种情况下我会怎么做呢?再次重写代码(break DRY)?尝试将这两个存储库合并在一起,并希望在其他某个时间点不需要任何方法(比如我可能有一个方法来检查是否使用了 userName - 也许我会在其他地方需要它)。
此外,如果我将它们合并在一起,我要么需要 2 个服务层进入同一个存储库,因为我认为拥有一个站点的 2 个不同部分的所有逻辑会很长,而且我必须有像 ValidateLogin()、ValdiateRegistrationForm() 这样的名称,valdiateLoginRetrievePassword() 等
或者无论如何都调用存储库并且只是有一个听起来很奇怪的名字?
似乎很难创建一个具有足够通用名称的存储库,以便您可以在应用程序的许多地方使用它并且仍然有意义,而且我认为在存储库中调用另一个存储库不是一个好习惯?
在使用存储库模式时我做错了一件事-就像您一样,我认为该表与存储库 1:1 相关。当我们应用领域驱动设计中的一些规则时 - 分组存储库问题通常会消失。
存储库应按 Aggregate root 而不是表。这意味着 - 如果实体不应该单独存在(即 - 如果您有一个参与特定 Registration
的 Registrant
) - 它只是一个实体,它不需要存储库,它应该被更新/创建/检索通过它所属的聚合根的存储库。
当然 - 在许多情况下,这种减少存储库数量的技术(实际上 - 它更像是一种构建域模型的技术)不能应用,因为每个实体都应该是一个聚合根(这高度取决于你的域,我只能提供盲目猜测)。在您的示例中 - License
似乎是一个聚合根,因为您需要能够在没有 Registration
实体上下文的情况下检查它们。
但这并不限制我们使用级联存储库(如果需要,Registration
存储库可以引用 License
存储库)。这并不限制我们直接从 Registration
对象引用 License
存储库(最好通过 IoC)。
尽量不要通过技术提供的复杂性或误解来推动您的设计。仅仅因为您不想构建 2 个存储库而在 ServiceX
中对存储库进行分组并不是一个好主意。
最好给它一个合适的名称 - RegistrationService
即
但一般应避免服务 - 它们通常是导致 anemic domain model 的原因。
编辑:开始使用 IoC。它真正减轻了注入依赖项的痛苦。而不是写:
var registrationService = new RegistrationService(new RegistrationRepository(),
new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());
你将能够写:
var registrationService = IoC.Resolve<IRegistrationService>();
Ps 使用所谓的 common service locator 会更好,但这只是一个例子。
为了解决这个问题,我开始做的一件事是实际开发包装 N 个存储库的服务。希望您的 DI 或 IoC 框架可以帮助使这更容易。
public class ServiceImpl {
public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { }
}
那有意义吗?另外,我知道在这个庄园里谈到服务可能会或可能不会真正符合 DDD 原则,我这样做只是因为它似乎有效。
我正在做的是我有一个抽象基类,定义如下:
public abstract class ReadOnlyRepository<T,V>
{
V Find(T lookupKey);
}
public abstract class InsertRepository<T>
{
void Add(T entityToSave);
}
public abstract class UpdateRepository<T,V>
{
V Update(T entityToUpdate);
}
public abstract class DeleteRepository<T>
{
void Delete(T entityToDelete);
}
然后,您可以从抽象基类派生存储库并扩展您的单个存储库,只要通用参数不同,例如;
public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>,
ReadOnlyRepository<string, IRegistrationItem>
ETC....
我需要单独的存储库,因为我们确实对某些存储库有限制,这为我们提供了最大的灵活性。希望这可以帮助。
我有这个作为我的存储库类,是的,我在表/区域存储库中进行了扩展,但有时我仍然必须打破 DRY。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MvcRepository
{
public class Repository<T> : IRepository<T> where T : class
{
protected System.Data.Linq.DataContext _dataContextFactory;
public IQueryable<T> All()
{
return GetTable.AsQueryable();
}
public IQueryable<T> FindAll(Func<T, bool> exp)
{
return GetTable.Where<T>(exp).AsQueryable();
}
public T Single(Func<T, bool> exp)
{
return GetTable.Single(exp);
}
public virtual void MarkForDeletion(T entity)
{
_dataContextFactory.GetTable<T>().DeleteOnSubmit(entity);
}
public virtual T CreateInstance()
{
T entity = Activator.CreateInstance<T>();
GetTable.InsertOnSubmit(entity);
return entity;
}
public void SaveAll()
{
_dataContextFactory.SubmitChanges();
}
public Repository(System.Data.Linq.DataContext dataContextFactory)
{
_dataContextFactory = dataContextFactory;
}
public System.Data.Linq.Table<T> GetTable
{
get { return _dataContextFactory.GetTable<T>(); }
}
}
}
编辑
public class AdminRepository<T> : Repository<T> where T: class
{
static AdminDataContext dc = new AdminDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["MY_ConnectionString"].ConnectionString);
public AdminRepository()
: base( dc )
{
}
我还有一个使用 Linq2SQL.dbml 类创建的数据上下文。
所以现在我有一个标准存储库,实现了 All 和 Find 等标准调用,并且在我的 AdminRepository 中我有特定的调用。
尽管我不认为,但没有回答 DRY 的问题。
我建议你看看Sharp Architecture。他们建议每个实体使用一个存储库。我目前在我的项目中使用它,并对结果感到满意。
存储库模式是一种糟糕的设计模式。我与许多旧的 .Net 项目合作,这种模式通常会导致可以避免的“分布式事务”、“部分回滚”和“连接池耗尽”错误。问题是该模式试图在内部处理连接和事务,但这些应该在控制器层处理。 EntityFramework 也已经抽象了很多逻辑。我建议使用服务模式来重用共享代码。
不定期副业成功案例分享