asp.net 如何正确使用仓库模式?

gcxthw6b  于 2023-10-21  发布在  .NET
关注(0)|答案(7)|浏览(159)

我想知道我应该如何分组我的仓库?就像我在ASP.NET MVC上看到的例子一样,在我的书中,他们基本上对每个数据库表使用一个存储库。但这似乎是一个很多的存储库,导致你不得不调用许多存储库后,嘲笑和东西。
所以我想我应该把它们分组。但我不知道如何将它们组合起来。
现在我做了一个注册仓库来处理我所有的注册事宜。然而,我需要更新四个表,之前我有三个存储库来做这件事。
例如,其中一个表是许可证表。当他们注册时,我查看他们的密钥并检查它是否存在于数据库中。现在,如果我需要在其他地方检查这个许可证密钥或该表中的其他内容,而不是注册,会发生什么?
一个点可以登录(检查密钥是否未过期)。
在这种情况下我会怎么做?重新编写代码(中断DRY)?尝试将这两个仓库合并在一起,并希望在其他时间点不需要任何方法(比如我可能有一个方法来检查是否使用了userName-也许我在其他地方需要它)。
此外,如果我将它们合并在一起,我需要两个服务层进入同一个存储库,因为我认为为站点的两个不同部分提供所有逻辑会很长,并且我必须有像ValidateLogin(),ValdiateRegistrationForm(),ValdiateLoginRetrievePassword()等这样的名称。
或者打电话给仓库,只是有一个奇怪的冠冕堂皇的名字?
似乎很难使一个存储库有一个足够通用的名称,这样你就可以在应用程序的许多地方使用它,而且仍然有意义,我不认为在一个存储库中调用另一个存储库是一个好的做法?

htzpubme

htzpubme1#

在使用存储库模式时,我做错了一件事--就像你一样,我认为这个表与存储库1:1相关。当我们应用domain-driven design中的一些规则时,分组存储库的问题通常会消失。
存储库应该按照Aggregate root而不是表。这意味着,如果实体不应该单独存在(即,如果您有一个Registrant参与到一个特定的Registration中),那么它只是一个实体,并且它不需要存储库。它应该通过它所属的聚合根的存储库进行更新/创建/检索。
当然,在许多情况下,这种减少存储库数量的技术(实际上,它更像是一种构建域模型的技术)不能应用,因为每个实体都应该是一个聚合根(这高度依赖于您的域,我只能提供盲目的猜测)。在您的示例中,License似乎是一个聚合根,因为您需要能够在没有Registration实体的任何上下文的情况下检查它们。
但这并不限制我们使用级联存储库(如果需要,允许Registration存储库引用License存储库)。这并不限制我们直接从Registration对象引用License存储库(最好通过IoC)。
只是尽量不要通过技术提供的复杂性或误解来驱动您的设计。仅仅因为不想构建两个存储库而在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,但这只是一个例子。

6l7fqoea

6l7fqoea2#

为了解决这个问题,我已经开始做的一件事是实际开发 Package N个存储库的服务。希望您的DIIoC框架可以帮助您更轻松地实现这一点。

public class ServiceImpl {
    public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { }
}

这有道理吗此外,我明白,在这个庄园里谈论服务可能会或可能不会实际上符合DDD原则,我只是这样做,因为它似乎工作。

vatpfxk5

vatpfxk53#

我有一个抽象基类,定义如下:

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>

等等...
我需要独立的仓库,因为我们对一些仓库有限制,这给了我们最大的灵活性。

8oomwypt

8oomwypt4#

我把它作为我的仓库类,是的,我在表/区域仓库中扩展了它,但有时我仍然需要破坏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中,我有了特定的调用。
但它没有回答干燥的问题,我不认为。

au9on6nz

au9on6nz5#

使用FluentNHibernate的通用Repository实现的Here is an example。它能够持久化您为其编写了Map器的任何类。它甚至能够根据Map器类生成数据库。

mqxuamgl

mqxuamgl6#

我建议你看看Sharp Architecture。他们建议每个实体使用一个存储库。我目前正在我的项目中使用它,并且对结果非常满意。

nimxete2

nimxete27#

Repository模式是一个糟糕的设计模式。我使用过许多旧的.NET项目,这种模式通常会导致“分布式事务”,“部分回滚”和“连接池耗尽”错误,这些错误是可以避免的。
问题是,该模式试图在内部处理连接和事务,但这些应该在控制器层处理。而且Entity Framework已经抽象了很多逻辑。
我建议使用服务模式来重用共享代码。

相关问题