【发布时间】:2020-04-16 14:42:06
【问题描述】:
我有一个使用 EF Core 3.1 访问其数据的网站。它使用的主表是 [Story] 每个用户可以存储有关每个故事的一些元数据 [StoryUserMapping]。我想做的是当我读入 Story 对象时,EF 会自动加载该故事的元数据(如果存在)。
类:
public class Story
{
[Key]
public int StoryId { get; set; }
public long Words { get; set; }
...
}
public class StoryUserMapping
{
public string UserId { get; set; }
public int StoryId { get; set; }
public bool ToRead { get; set; }
public bool Read { get; set; }
public bool WontRead { get; set; }
public bool NotInterested { get; set; }
public byte Rating { get; set; }
}
public class User
{
[Key]
public string UserId { get; set; }
...
}
StoryUserMapping 具有复合键 ([UserId], [StoryId])。
我想看到的是:
public class Story
{
[Key]
public int StoryId { get; set; }
public bool ToRead { get; set; } //From user mapping table for currently logged in user
public bool Read { get; set; } //From user mapping table for currently logged in user
public bool WontRead { get; set; } //From user mapping table for currently logged in user
public bool NotInterested { get; set; } //From user mapping table for currently logged in user
public byte Rating { get; set; } //From user mapping table for currently logged in user
...
}
有没有办法在 EF Core 中做到这一点?我当前的系统是将 StoryUserMapping 对象作为 Story 对象的属性加载,然后在 Story 对象上使用 Non-Mapped 属性访问器,如果 StoryUserMapping 对象存在,则读取该对象。这通常感觉像是 EF 可能更优雅地处理的事情。
用例
设置:我有 100 万个故事,1000 个用户,最坏的情况下,我有一个 StoryUserMapping 每个故事:10 亿条记录。
用例 1:我想查看我(登录用户)标记为“阅读”且超过 100,000 字的所有故事
用例 2:我想查看我没有标记为 NotInterested 或 WontRead 的所有故事
我不关心每个故事查询多个 StoryUserMappings,例如我不会问这个问题:哪些故事被超过 n 个用户标记为已读。如果将来发生变化,我宁愿不限制这一点,但如果我需要这样做就可以了。
【问题讨论】:
-
我要问的第一个问题是为什么你需要根
Story对象中的这些数据吗?Story及其导航属性是否不够?您是否通过 API 返回这些数据?我不会将带有[NotMapped]属性的聚合属性添加到Story类中,因为这表明当有更好的方法时,您会在实体模型中硬塞数据。 -
我同意这是代码异味。我想要 Story 对象中的属性的主要原因是为了方便。我将这些字段用作 Web 应用程序的 cshtml 页面上的过滤器。如果效果更好,我很乐意将它们留在子对象中。更重要的是,我不能仅仅获得 Story 与 StoryUserMapping 的正常关系,因为我无法传入 Current UserId(或者我不知道如何)
-
在这种情况下,我建议您考虑使用视图模型/dto/aggregate 对象来传输您的视图数据。您不希望扭曲实体以适应它们在视图中的外观 - 您的控制器/服务逻辑将需要映射/按摩实体数据以适应输出/视图。阅读创建 MVC Web 应用程序时的最佳实践,以及如何最好地将您的关注点分离到应用程序中的责任“层”:)
-
我在原始问题中添加了一些用例。我在建议的方法中看到的问题是,如果我尝试满足用例 1,我查询所有超过 100,000 个单词的故事,得到 1,000 条记录 * n 个故事。然后必须手动过滤那些我标记为“待读”的故事。这是一个潜在的大量数据传输,最终会导致很少的记录。
-
感谢您添加一些用例 - 当然有助于了解您想要实现的目标。不过,我关于使用聚合 viewmodel/dto 对象的原始评论仍然有效。您可以利用 EF/LINQ 的强大功能使用现有模型查询正确的数据,然后然后将结果映射到并显示它们的聚合对象。我很快会添加一个答案,应该可以帮助你:)
标签: c# entity-framework-core entity-framework-core-3.1