我之前编写的一些代码使用该Find()方法通过主键检索单个实体:
return myContext.Products.Find(id)
Run Code Online (Sandbox Code Playgroud)
这很有效,因为我将这段代码放入一个通用类中,并且每个实体都有一个不同的字段名称作为其主键。
但是我不得不替换代码,因为我注意到它正在返回缓存的数据,并且每次调用时我都需要它从数据库中返回数据。微软的文档证实这是Find().
所以我把我的代码改成使用SingleOrDefaultor FirstOrDefault。我没有在文档中找到任何说明这些方法返回缓存数据的内容。
现在我正在执行这些步骤:
SingleOrDefault
或将实体检索到新的实体变量中FirstOrDefault。返回的实体在该Description字段中仍然具有旧值。
我已经运行了 SQL 跟踪,并验证了在第 3 步期间正在查询数据。这让我感到困惑 - 如果 EF 正在往返数据库,为什么它返回缓存数据?
我在网上搜索过,大多数答案都适用于该Find()方法。此外,他们提出了一些解决方案,这些解决方案仅仅是解决方法(处理DbContext并实例化一个新的)或对我不起作用的解决方案(使用该AsNoTracking()方法)。
如何从数据库中检索我的实体并绕过 EF 缓存?
我在Entity Framework Core中遇到了一个DELETE CASCADE问题,我似乎找不到很好的解决方案。
这是我的模型的超级简化版:
User {UserID, Name}
Recipe {RecipeID, UserID}
Ingredient {IngredientID, UserID}
RecipeIngredient {RecipeID, IngredientID} *RecipeIngredient is the many-to-many table.
Run Code Online (Sandbox Code Playgroud)
Recipe和Ingredient都将UserID标记为[Required],并且RecipeIngredient将RecipeID和IngredientID标记为[Required]。
问题是SQL将不会创建数据库,因为存在多个到RecipeIngredient的级联删除路径(“引入FOREIGN KEY约束...可能会导致循环或多个级联路径”)。
所以我被困住了……我已经解决了一些想法,但是没有任何事情奏效。
这里有设计解决方案吗?我想保留我的外键,因为强制执行它是有意义的,但是如果有设计解决方案,我会接受的。
我的下一个想法是删除所有指向用户的FK-我必须在DELETE期间通过C#代码强制执行参照完整性,并且可以在CREATE期间使用[Required]强制输入数据。出现的问题-[必需]创建一个FK,并添加“ ON DELETE CASCADE”,这使我们重新回到多级联删除路径问题中。我真的很想保留[Required],因为它与Razor页面的集成巧妙,客户端验证和错误等。
下一个想法,在OnModelCreating(...)中将级联行为设置为SetNull:
modelBuilder.Entity()。HasOne(i => i.User).WithMany(u => u.Ingredients).OnDelete(DeleteBehavior.SetNull);
modelBuilder.Entity().HasOne(r => r.Source).WithMany(s => s.Recipes).OnDelete(DeleteBehavior.SetNull);
但这引发了一个异常,因为即使我在“成分和配方”中的属性设置为Nullable:
[Required(ErrorMessage = "User ID is required.")]
public Nullable<int> UserID { get; set; }
Run Code Online (Sandbox Code Playgroud)
...由于[Required]属性,EF仍将其创建为NOT NULL数据库列。
有什么解决方案?据我所知,我应该将所有FK删除给User,然后尝试将其强制作为CREATE上的必填字段,但是我看不到要使用数据注释来做到这一点的方法。将此逻辑保留在我的代码优先模型中。