Entity Framework:如果允许模型处于非法状态,在某些场景下,记得清空DbContext

时间:2024-10-15 23:36:20

Entity Framework:如果允许模型处于非法状态,在某些场景下,记得清空DbContext

背景

之前写过两篇文章介绍模型的合法性:

  1. DDD:关于模型的合法性,Entity.IsValid()合理吗?
  2. .NET:关于数据模型、领域模型和视图模型的一些思考

今天讨论的问题其实是关于“主键映射”的,只是其中还涉及一种决策:“允许模型处于非常状态”。

测试代码

Entity Framework:如果允许模型处于非法状态,在某些场景下,记得清空DbContext
 1         public static void Do()
2 {
3 Database.SetInitializer<MyDbContext>(new DropCreateDatabaseAlways<MyDbContext>());
4
5 using (var context = new MyDbContext())
6 {
7 /****************添加一个Note*****************/
8 var note = new Note { Name = "合法名字" };
9 context.Set<Note>().Add(note);
10 context.SaveChanges();
11 /****************添加一个Note*****************/
12
13 try
14 {
15 /****************让Note处于非法状态*****************/
16 var firstNote = context.Set<Note>().First();
17 firstNote.Name = "非法名称";
18 if (firstNote.Name == "非法名称")
19 {
20 throw new InvalidOperationException("非法名称");
21 }
22 /****************让Note处于非法状态*****************/
23 }
24 catch
25 {
26 //这里会出现BUG,显示的还是非法名字。
27 Console.WriteLine(context.Set<Note>().First().Name);
28
29 //清空DbContext以后就对了。
30 foreach (var entity in context.ChangeTracker.Entries())
31 {
32 entity.State = EntityState.Detached;
33 }
34 Console.WriteLine(context.Set<Note>().First().Name);
35 }
36 }
37 }
Entity Framework:如果允许模型处于非法状态,在某些场景下,记得清空DbContext

分析

第一个输出之所以不是期望的结果是因为EntityFramework内置了主键映射模式,内存状态还是处于非法状态,虽然First会导致一次数据库往返。

第二个输出之所以正确是因为清空了主键映射,这样会导致重新用数据库的内容填充主键映射。

结论

出现异常最好终止线程或程序的执行,上边这种BUG是因为使用了一种异常反模式:“把异常作为正常的逻辑处理流程”。

备注

这个错误我犯过,后来的朋友也犯过。