【问题标题】:Domain model doubts领域模型疑惑
【发布时间】:2010-06-19 18:19:26
【问题描述】:

一方面,我想编写一个杀手级应用程序(在 ASP.NET MVC 中);) 但另一方面,我是否应该不惜一切代价坚持所谓的“最佳实践”,我有很多疑问。所以我有一个设计问题,我真的希望你能帮助我。

想象一个标准的博客。我想显示 10 个最近的帖子。我的数据库有标准
Posts, Categories, Tags, PostTags
表。因此,作为自然结果,我的域 Post 类具有如下属性:

public Category Category { get; set; }
public virtual ICollection<Tag> Tags { get; set; }

我使用带有 POCO 支持的 EF4。我使用标准查询加载数据:

from p in context.Posts.Include("Category").Include("Tags")
select p

但是我为什么要加载整个 Post 类(例如这两个属性),当页面上我想要显示的所有内容(除了帖子本身)都是指向类别和每个标签的链接时,所以我需要的所有列分别是:
[Categories].[Name], [Categories].[Slug], [Tags].[Name], [Tags.Slug]

我不需要整个 Category 或 Tag 实例(在数据库的相应表中可能有 100 列)!我想当一个网站收到很多请求时,它确实很重要。所以最好不要加载所有列(避免可怕的SELECT *)。

我想我可以在我的域中添加一个新类,比如:ShortPost。但我觉得这不是我的领域! Post 是模型,ShortPost 是……嗯,只是完整 Post 的一部分。此外 - 我觉得这个 ShortPost 就像修改/调整域(模型)只是为了取悦视图。

总结一下:当在视图端我不需要整个对象时,我真的应该加载整个模型实例吗?您能告诉我一些首选的解决方案/方式/等吗?

【问题讨论】:

    标签: asp.net-mvc entity-framework dns


    【解决方案1】:

    不使用实体阅读如何? 这是命令-查询分离模式的一个特点。

    如果您的视图需要的唯一字段是 [Categories].[Name]、[Categories].[Slug]、[Tags].[Name]、[Tags.Slug]

    然后创建一个 DTO 来表示它,并通过投影您的实体或直接查询您的数据存储来填充它。

    public class PostDto
    {
        public string CategoryName { get; set; }
    
        public string CategorySlug { get; set; }
    
        public string TagName { get; set; }
    
        public string TagSlug { get; set; }
    
    }
    

    【讨论】:

    • 是的,它会消除 SELECT *,但 PostDTO 在概念上不属于模型,所以不应该在我的存储库中使用它来查询数据库,不是吗?
    • 它属于 ViewModel 但不应该在您的存储库中引用。在 CQS 中,您不使用 Repositories 来填充 ViewModel,而是使用薄查询层和 Repositories 仅用于写入操作或命令。
    【解决方案2】:

    加载完整的域模型 - 这样您就可以缓存它们并在缓存中拥有完整的对象。

    在缓存中部分填充对象会令人困惑。

    【讨论】:

    • 好的,这是一个答案......但作为反驳我会说:我害怕加载完整的实例(这意味着例如来自数据库的 200 列)会非常缓慢- 在 webapp 中,性能非常重要。
    • 我完全忘记了缓存...这样就可以了。非常感谢这个概念:)
    【解决方案3】:

    鉴于你的例子 - 我会去:

    public class Post
    {
        public Category Category {get;set;}
    }
    public class Tag
    {
        public Post {get;set;}
    }
    

    这样就更容易准确地查询给定帖子所需的标签何时您需要它们(您查询标签以查找与帖子匹配的标签,而不是查询帖子的标签 - 因此给出您可以对它们进行分页、过滤等)。

    尽我所能,我倾向于避免使用集合(除非它是没有父对象就无法存在的值对象)。根据我的经验,维护起来会容易得多。

    如果您在某些时候需要显示有关您的帖子的统计信息(它附加了多少标签等等) - 您可以仅使用您需要的数据对您的数据进行“视图”(相当于表中的视图)你的数据库)。视图在您的域之外 - 因此您无需遵守域的规则。然后,当您进入“编辑模式”时,您会加载完整的实体。

    【讨论】:

    • 谢谢小费,但它没有回答我的问题。我在问是否可以(从“最佳实践”的角度)执行 SELECT * 以便拥有完全加载的实体,而不是拥有许多我根本不需要的数据(在我的视图中)。
    • 简短的回答是视情况而定。选择 * 只有在出现问题时才会出现问题(通常阅读:性能)。只有在遇到问题时才进行此类优化。
    • 嗯,这是对加载所有数据的第二次“是”投票...我开始认为我保护过度了 :)
    • 呵呵 - 我已经尝试了太多次优化才知道经过数小时的努力工作后才知道我在 250 毫秒的查询中赢得了 5 毫秒是一个问题:)。
    猜你喜欢
    • 2010-12-20
    • 2014-01-05
    • 2012-09-04
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-04
    相关资源
    最近更新 更多