【问题标题】:Repository Pattern: good or bad?存储库模式:好还是坏?
【发布时间】:2023-03-19 06:55:01
【问题描述】:

在阅读了 ASP.NET MVC 3.0 项目中存储库设计模式的好处(和使用)之后,我遇到了一个让我感到困惑并开始质疑该模式的好处的问题。也许有人可以帮助我澄清这一点。

我有以下 3 个表:

  • -用户 (parent)
  • -UserLead (child of User)
  • -UserLeadNotes (child of UserLead)

大致上,表格及其关系设计如下:

  • 用户 [Id]
  • UserLead [Id, UserId(外键)]
  • UserLeadNotes [Id, UserLeadId(外键)]

我有一个包含基本 CRUD 方法的 BaseRepository。 (IEnumerable<TEntity> Get(), TEntity GetByID(), Insert(), Delete(), etc…)

有了这个,我还有一个Service Layer,它会在需要时调用适当的存储库。

简而言之,应用程序显示一个 UserLead 并允许用户向该 UserLead 添加/删除注释(在 UserLeadNotes 表中存储/删除)。添加/删除注释是通过 Ajax 调用完成的。 删除一条笔记会传递我希望删除的笔记的“id”

现在……在我真正删除笔记之前,我需要确保该笔记真正属于当前登录的用户(User.Identity.Name aka UserId

考虑到我的方法deleteUserNote(int noteId) 只接收“noteId” 参数AND 考虑到我的UserLeadNotes TABLE 没有UserId 上有外键,我需要什么要做的是添加一个

.Include(“UserLead”)

在我的_userLeadNoteRepository 里面有类似的东西:

UserLeadNote userLeadNote = _userLeadNoteRepository
                .AllIncluding(p => p.UserLead)
                .FirstOrDefault(p => p.UserLeadNoteID.Equals(noteId) 
                   && p.UserLead.UserID.Equals(User.Identity.Name));

然后我会删除我刚刚找到的 UserLeadNote 对象:

_userLeadNoteRepository.Delete(userLeadNote);

问题:

按照上述方法,这将迫使我 a) 为我的 UserLeadNotes 和 b) 创建一个存储库,因为 .Include() 找到的 userLeadNote 对象将具有一个名为 UserLead 的属性,其中包含所有定义的字段在 UserLead 表中。

如果我的 UserLead 表恰好有 14 个字段,其中 10 个字段是 ntext,这意味着我会无缘无故地加载/保存太多信息!

如果我要使用,而不是 Lambda 表达式,绕过存储库并直接使用我的上下文的 Linq 语句:

using(MyContext db = new MyContext ())
            {
                var query =
                    from uln in db.UserLeadNote
                    join ul in db.UserLead on uln.UserLeadID equals ul.UserLeadID
                    where uln.UserLeadNoteID == userLeadNoteID
                        && ul.UserID == User.Identity.Name
                    select uln;

                var userLeadNote = query.FirstOrDefault();

                db.UserLeadNote.Remove(userLeadNote);

                db.SaveChanges();
            }

这种方法会不会更有效,因为它不会从 UserLead 表中带回那些不必要的字段? (例如那 10 个 ntext 字段)。

除非我没有正确使用存储库模式,或者这可能是实体框架问题,否则我想知道任何人的想法!

请记住,我知道使用存储库模式的好处,但很好奇这是否是人们遇到的某种问题。如果是这样,他们是否决定放弃 Pattern 并使用 Linq 语句直接使用他们的上下文。

两害相权取其轻?

【问题讨论】:

  • 我在几个项目中使用了该模式,但为了直接进入上下文而放弃了它。如果您继续使用该模式,您应该阅读Aggregate Roots。您不希望每个表/实体都有一个 repo,只需要您的核心。我通常为复杂的业务逻辑/关系保留完整的 DDD。 devlicio.us/blogs/casey/archive/2009/02/16/…
  • 我现在更好地理解了我的 UserLead 和 UserLeadNotes 表将被视为一个聚合。所以我的 UserLead 表将被视为聚合根。这意味着我应该只有一个用于该聚合根表的存储库,并从该根导航到我的孩子。考虑到这一点,让我的单个 UserLead 存储库如何允许我导航到我的孩子并获得 FirstOrDefault() 子对象而不加载父级的附加字段?也许你是对的;我应该放弃存储库模式并直接从我的服务层调用/使用我的上下文

标签: asp.net-mvc repository-pattern


【解决方案1】:

总之,

阅读 Ryan 和 Rouen 的帖子后,似乎为每个实体创建一个存储库可能不是合适的方法。如果我有一个子(或子的子)实体,我应该改为创建一个父存储库并通过子(或子的子)导航。

我遇到的问题是,当尝试删除子实体的子实体(没有父实体的外键)时,我必须 .Include(“”) 那些其他“上层”表。 (在我的情况下,它只有一个表,即父表,但很容易必须删除一个孩子的孩子的孩子,并且必须Include()许多“父母/上层”表)。

最后,包括 Parent 表创建了一个包含 Parent 的所有字段的属性,在我的例子中,这被认为是“获取”太多信息来完成我手头的简单任务。

如果我要放弃使用存储库模式,而是直接使用上下文,则可以避免这个所谓的问题。

对于某些人来说,这可能不是问题(或者他们根本不知道发生了什么),而对于其他人来说,使用该模式比它可能具有的缺点更重要。

我还没有决定完全放弃存储库模式,因为我喜欢它带来的东西。

谢谢大家。

【讨论】:

  • 很高兴我能帮上忙。真正让我想到我过度使用存储库模式的是 Ayende 博客上的一系列帖子。 ayende.com/blog/tags/design 从“罪恶的工资”开始阅读,然后可能连续 12 个帖子(向下阅读页面)绝对是黄金。
  • @Vlince,我有相同的“为我手头的简单任务获取太多信息”,其中包含多个调用。考虑存储库但不确定:stackoverflow.com/questions/17529796/…
【解决方案2】:

试着看这里:

asp.net mvc page is not showing properties from associated objects

我对这种滥用通用存储库模式的解释/意见给出了答案

【讨论】:

  • 感谢您的帖子!所以最后,就像 Ryan 的评论中提到的那样,我可能应该放弃存储库模式,并直接使用我的 Context 将我的查询直接合并到我的服务层中。这将提高性能并在没有额外数据/字段的情况下准确返回我想要的内容。放弃该模式的代价是现在我的服务层将与我的数据库紧密耦合。哦,好吧……只要我意识到这一点。谢谢
猜你喜欢
  • 1970-01-01
  • 2010-11-12
  • 2011-02-01
  • 2011-09-12
  • 2014-06-30
  • 2011-02-20
  • 2015-07-20
  • 2014-10-31
  • 1970-01-01
相关资源
最近更新 更多