Winforms 中的 Context.SaveChanges
Posted
技术标签:
【中文标题】Winforms 中的 Context.SaveChanges【英文标题】:Context.SaveChanges in Winforms 【发布时间】:2020-12-24 08:52:40 【问题描述】:这是基本的 winform 应用程序,没有服务或介于两者之间的任何东西。我正在使用实体框架从数据库中获取一些记录。下面的代码在一个名为 PersonRepository 的类中。
var obj = Context.Persons.Where(u=>u.Id==20);
obj.RegisterDate = obj.RegisterDate.ToMountainStandardTime();
return obj;
ToMountainStandardTime 是日期类型的扩展方法。
现在,在我拉出这条记录并显示到 UI 之后。用户在屏幕上执行一些操作,并根据要求在另一个名为“活动”的表中插入记录。用户不需要在 Person 表中保存任何内容。
做完自己的事情后,像这样
Context.Activities.Add(newActivityObject);
Context.SaveChange();
这两种方法都在同一个类中。除了在活动表中添加新对象外,它还更新所选人员类别的注册日期。 我知道原因,这个 Context 对象在 PersonRepository 类的构造函数中初始化并被该类中的所有方法使用。
我的大部分经验是通过 restful 服务使用它,我不需要太多担心这些事情,因为对于每个请求,我们都会创建新的上下文实例。
我可以通过在像这样编辑它之前从上下文中分离对象来简单地处理它
Context.Entry(obj).State = EntityState.Detached;
但是想知道是否有更好的方法来处理这个问题?
【问题讨论】:
您可以更改为单例上下文。 【参考方案1】:您有几个选择需要考虑。首先,实体要么只能依赖于在它们被读取的 DbContext 范围内有效,要么需要分离并重新连接以在 DbContext 边界之间进行转换。
要使实体在其 DbContext 范围内,您的选择是:
-
长寿命(即单例)DbContext。
短期项目实体到 POCO 容器并根据需要按需重新加载实体。
第三种选择是使用短期 DbContexts,然后手动管理实体的分离和重新附加。
我从不推荐第三个选项,因为它容易出错并鼓励过时数据覆盖等问题。它在概念上很简洁,但在实践中往往会成为令人头疼的重复来源。
对于自身运行时生命周期相对较短的小型应用程序,长生命周期的 DbContext 可能是一个易于实现的选项。长寿命 DbContext 的最大缺点是:
使上下文长时间处于活动状态可能意味着随着更多实体被缓存,性能会随着时间的推移而下降。随着缓存的增长,对实体执行操作(更新/插入)的时间增加,缓存实体的性能更好的假设可能会被放错地方,因为 EF 将在缓存中查找可能与新的/更改的实体值相关联的实体引用. 如果多个实例正在运行,则上下文正在加载的数据将变得陈旧,或者外部进程可以修改数据状态。默认情况下,EF 将返回缓存的副本,如果怀疑过时,必须手动重新加载。对于大型应用程序或长时间运行的应用程序,我强烈倾向于使用依赖 POCO ViewModel/DTO 的短期 DbContext 来获取视图持续时间数据状态。这意味着通过 Select
或 Automapper 的 ProjectTo
利用 Projection 按需从实体加载相关数据以传递给视图,然后按 ID 重新加载实体,并在验证行版本号后在更新期间传输数据或使用更改的状态值执行操作/时间戳来检测可能的陈旧数据状态。通过 PK 重新加载实体及其相关数据非常快。
这不仅避免了尝试处理分离实体的复杂性/混乱,(并且无论如何都要重新加载数据状态以防止过时的覆盖),而且它可以为许多场景带来更优化的数据读取操作和索引利用率,尤其是在事物比如只需要特定表中的几个值而不是读取整个实体图的搜索结果。将实体传递给视图的一个主要罪过是试图通过避免急切加载和禁用延迟加载以将“未使用”关系保留为 #null 或什至仅使用几个字段填充实体类对象以用作视图模型来避免额外的数据读取使用.Select
会导致错误或错误的假设/在以后的代码中被覆盖。实体应始终表示数据行的完整(或可完成)状态。作为数据域状态和视图状态的双重用途实体正在自找麻烦。期望一个实体的方法永远不需要关心他们得到的是一个完整的实体还是一个部分完整的实体。
【讨论】:
以上是关于Winforms 中的 Context.SaveChanges的主要内容,如果未能解决你的问题,请参考以下文章