gpt4 book ai didi

c# - 如何以正确的方式实现存储库模式?

转载 作者:可可西里 更新时间:2023-11-01 07:59:01 28 4
gpt4 key购买 nike

在为我的 ASP.NET 项目实现存储库模式时,我遇到了一些无法解决的问题。所以我有几个关于如何以正确的方式实现存储库模式的问题。

根据我的经验,我认为只有在我的应用程序中没有行为的类/模型,在它们的存储库旁边并不是好的 OOP。但是,这就是我实现存储库模式的方式。我只是在任何需要存储库实例的地方制作,以执行一些操作。这种方法的结果是我所有的域类都没有行为。

它们只是没有方法的保存数据的对象。我的老师对我说,我用的是瘦模型,我应该努力做胖模型。作为对该反馈的回应,我在类中实现了一些业务逻辑,但遇到了一些问题:

场景:

我的 User 类有一个 Friends 列表,其中包含 User 对象,代表某个用户的 friend 。向用户添加新 friend 时,域类方法会检查“ friend ”是否已存在于 friend 列表中。如果没有,他将被添加到列表中。这些更改需要发送到数据库以进行持久化。

我知道这必须在每个域类的存储库中完成,但是对存储库方法的调用属于应用程序架构中的什么地方?

现在我在域类方法本身中调用存储库方法,以持久保存对数据库的更改:

public void AddFriend(User friend)
{
foreach(User f in Friends)
{
if(f.Username == friend.Username)
{
throw new Exception(String.Format("{0} is already a friend.", friend.Username));
}
}

Friends.Add(friend);
userRepo.AddFriend(this.Id, friend.Id);
}

这是一个好方法吗,出于某种原因我认为它不是。关于单元测试,我们需要使用这种方法进行一些依赖注入(inject),这对我来说它不是一个独立的类(良好的可测试单元)。我读过一些人的帖子,说他们使用额外的服务层或其他东西。我认为这里需要这种抽象,但是某个服务层是什么样的?里面有什么,有哪些方法等?

我看到其他一些学生在域类中使用静态方法,这些方法提供添加新对象、更新对象、删除对象和获取所有对象等功能。

例子:

public class Tram
{
private static TramRepository Repo = new TramRepository(new DBTram());

public static void AddTram(int tramID, TramType type, int lineNr)
{
Tram tram = new Tram(tramID, type, TramStatus.depot, lineNr, true, null);
Repo.AddTram(tram);
}

public static List<Tram> GetAll()
{
Repo.GetAll();
}
}

我发现在域类中使用一种方法将新实体添加到数据库是一件很奇怪的事情,该实体本身就是该实体。同样对于 GetAll() 方法,我认为在类本身中有一个获取所有电车的方法很奇怪。所以一个电车对象可以得到所有的电车。我认为这是实现存储库模式的一种奇怪方式。我说得对吗?

那么,这里需要什么样的抽象呢?是否必须有一个额外的层?如果是这样,这一层是什么样子的? (示例代码)或者我搜索的方向错误,是否有另一种解决方案可以解决存储库模式的单元测试问题?

我每次都会遇到这个架构问题,确保我需要它来回答。

这个问题我很难解释清楚,希望大家理解。

最佳答案

你的问题绝对正常,但不要指望找到绝对的答案。欢迎来到软件行业!

这是我的看法:

  1. Is it good OOP to have an application that relies on an architecture that, next to their repositories, only has models/classes that hold values with no behaviour?

我认为您尝试实现存储库模式,但您错过了更高的架构 View 。大多数应用程序至少在 3 层中解耦: View (演示)、业务和数据访问。存储库模式发生在 DataAccess 中,这是您可以找到纯数据对象的地方。但是这个数据访问层被业务层使用,你会在业务层中找到一个域模型、具有业务行为和数据的类。单元测试工作必须在业务层的域模型上进行。这些测试不应该关心数据是如何存储的。

  1. Where do I call repository methods in the architecture of the application?

同样没有绝对的答案,但通常使用像业务服务这样的东西是有意义的。这些服务可以安排不同域对象之间的流,并将它们加载并保存在存储库中。这基本上就是您在 AddFriend 类中所做的,它属于业务层。

Regarding to unit testing, we need with this approach some dependancy injection, which says to me that it is not a independant class

业务服务通常依赖于存储库,这是单元测试的一个非常常见的情况。 Tram 类可以持有业务行为,并且仍然是独立的。 AddTram 业务服务需要一个存储库,并且依赖注入(inject)允许对其进行测试。

  1. Methods that insert, update and delete new entities in a database, are they supposed to be in a class itself?

对于这一点,我可以明确而响亮:请不要那样做,是的,CRUD 操作属于 Tram Repository。这当然不是业务逻辑。这就是为什么在您的示例中您需要两个不同层中的两个类:

  • Tram 可以是业务层的业务对象(这里没有 Crud 操作)
  • TramRepository 是需要存储 Tram 数据的对象(您将在其中找到 CRUD 操作)

"Because i have seen some other students making use of static methods in a domain class which provides these functionality"

使用静态方法显然不是一个好主意,这意味着任何人都可以通过您的对象存储数据,即使它应该处理业务案例。再次重申,数据存储不是业务案例,而是技术必需品。

现在公平地说,所有这些概念都需要在上下文中进行讨论才能有意义,并且需要根据每个新项目进行调整。这就是您的工作既艰巨又令人兴奋的原因:背景为王。

我还写了一个blog article以 MVVM 为中心,但我认为它可以帮助理解我的答案。

关于c# - 如何以正确的方式实现存储库模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41767133/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com