【问题标题】:Why adding new entity just to modify another one为什么添加新实体只是为了修改另一个实体
【发布时间】:2019-08-07 14:25:01
【问题描述】:

我正在阅读一个 ASP.NET Core 示例项目 (MSDN) 的源代码并尝试了解所有内容。

有一个编辑 razor 页面,它在<input> 字段中显示实体记录的值,允许用户查看和更改给定记录的不同字段。有这样一行:

Movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
...
_context.Attach(Movie).State = EntityState.Modified;

我不明白为什么它会添加一个新实体并将其EntityState 更改为Modified,而不是获取记录并更改它然后调用SaveChanges()

【问题讨论】:

  • 您的问题不清楚。此处未添加任何实体。事实上,它完全按照您所说的去做(从数据库中提取实体,对其进行修改,然后保存更改)。也许如果您发布更多代码或提供指向您正在查看的内容的链接,您的要求可能会更清楚。

标签: asp.net entity-framework asp.net-core entity-framework-core


【解决方案1】:

我的猜测是,他们的示例是在一次调用中加载电影,将其传递给视图,然后在另一个更新操作中,将修改后的实体从视图传递给控制器​​,控制器正在附加它,将其状态设置为已修改,然后调用保存更改。

恕我直言,这是一个非常糟糕的做法,原因有很多,我不知道微软为什么在示例中使用它(除了它使 CRUD 看起来很容易)。

  1. 通过将实体序列化到视图,您序列化的数据通常远远多于视图实际需要的数据。您向恶意或好奇的用户提供的有关您系统的信息比您应该提供的要多得多。
  2. 您一定会遇到双向引用的序列化程序错误。 (“A”引用了“B”,而“B”又引用了“A”)序列化程序(如 JSON)通常不喜欢这些。
  3. 当序列化程序“触及”引用时,您一定会遇到延迟加载调用的性能问题。在处理结果集合时,由此产生的延迟加载调用可能会完全破坏性能。
  4. 如果不启用延迟加载,您很容易遇到引用数据作为 #null 传递或可能不完整的集合的问题,因为 Context 可能在缓存中有一些引用数据,它可以拉取并关联到实体,但不是完整的子记录集。
  5. 通过将实体传回控制器,您将系统暴露给无意的修改,攻击者可以通过这些修改以您不希望修改的方式修改实体数据,然后当您附加它时,将状态设置为已修改,并保存,您将覆盖数据状态。 IE。更改 FK,或以其他方式更改您的 UI 不支持甚至显示的数据。
  6. 您一定会遇到过时数据问题,其中数据可能在您最初读取实体的点与保存点之间发生变化。附加和保存对并发数据采取了一种残酷的“后发制人”方法。

我的一般建议是: 1. 利用 Select 或 Automapper 的 ProjectTo 仅使用视图所需的字段填充 ViewModel 类。这避免了延迟加载的风险,并最大限度地减少了传递给客户端的数据。 (更快,并且不会透露任何关于您的系统的额外信息) 2. 绝对不相信来自客户的任何反馈。验证返回的视图模型对象,然后只有在您确信它是合法的之后,才从上下文中加载实体并复制适用的字段。这也让您有机会评估行版本控制以处理并发问题。

免责声明:您当然可以解决我指出的大多数问题,同时仍然来回传递实体,但是当有人只是默认附加和保存或延迟加载时,您肯定会为漏洞和错误的蔓延敞开大门开始潜入。

【讨论】:

    猜你喜欢
    • 2011-02-16
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 2012-08-02
    • 2020-12-14
    • 2014-04-29
    • 1970-01-01
    • 2011-10-29
    相关资源
    最近更新 更多