c# - C# 9 - 使用实体框架更新记录的仅初始化属性
问题描述
C# 9 引入了记录和仅初始化属性,以便更轻松地编写不可变引用对象。
我一直在尝试将旧的实体框架项目转换为使用这些功能,但我在具有仅初始化属性的不可变 C# 记录和尝试更改底层 SQL 记录之间遇到了一些摩擦。
也许我只是在逆流而上,但是是否有一种模式可以将 C# 类定义为不可变的仅初始化记录,但仍允许更新底层 SQL 数据?
我当前使用可变类的(工作)代码:
我的报告.cs
namespace MyNamespace
{
public sealed class MyReport
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ReportId { get; set; }
public DateTime ReportDate { get; set; }
public bool ReadyToUse { get; set; }
}
}
我的应用程序.cs
using (var dbContext = DbContext.Create(connectionString))
{
// create a new report
var myReport = new MyReport
{
ReportDate = reportDate,
ReadyToUse = false
};
dbContext.SaveChanges();
... do some other stuff ...
// update the report status
usageReport.ReadyToUse = true;
dbContext.SaveChanges();
}
但是,如果我将 MyReport 的实现更改为使用 C# 9 记录和仅初始化属性:
我的报告.cs
namespace MyNamespace
{
public sealed record MyReport
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ReportId { get; init; }
public DateTime ReportDate { get; init; }
public bool ReadyToUse { get; init; }
}
}
然后我开始收到错误:
CS8852 - 仅初始化属性或索引器只能在对象初始化器中分配
在线上
usageReport.ReadyToUse = true;
我对这个错误没有任何抱怨,因为您显然无法在构造函数之外更新仅初始化属性,但我想知道是否有一种在实体框架中使用仅初始化属性和可变 SQL 数据的好方法。
我想过这样做:
using (var dbContext = DbContext.Create(connectionString))
{
// create a new report
var myReport = new MyReport
{
ReportDate = reportDate,
ReadyToUse = false
};
dbContext.SaveChanges();
... do some other stuff ...
// update the report status
usageReport = usageReport with { ReadyToUse = true };
dbContext.SaveChanges();
}
但是我不知道如何告诉将dbContext
新的usageReport视为对基础SQL数据的更改而不触发大量删除和重新插入。
解决方案
您当然可以将 C# 9 记录与 Entity Framework 一起使用。您不能做的是将它们与“检索实体,更新其属性并调用.SaveChanges()
.
相反,您必须将记录的复制和更新语法与 DbContext.Update() 函数结合使用:
var report = dbContext.Set<MyReport>().AsNoTracking().First(...some linq query...);
var updatedReport = report with {ReadyToUse = true};
dbContext.Update(updatedRecord);
dbContext.SaveChanges();
重要提示:您需要调用.AsNoTracking ()
每个查询或禁用更改跟踪器以防止 EF 跟踪检索到的实体。如果你不这样做,它会在 ``.SaveChanges () '' 中抛出一个异常,说明另一个具有相同键的实体已经被跟踪。如果您决定将所有实体声明为记录,则禁用跟踪系统是最佳选择,将对应用程序的整体性能产生积极影响。
EXTRA:使用 F# 记录时,解决方案完全相同。
推荐阅读
- jekyll - Jekyll 自定义主题在 Github 页面上不起作用
- javascript - React Native - 分析来自 Firebase 的数据并在应用内显示
- java - 我在 AsyncTask 的 doInBackground () 中收到错误
- node.js - npm 错误!enoent ENOENT:没有这样的文件或目录,打开'/app/package.json'
- javascript - TypeError:无法读取 React 和 Redux 中未定义的属性“代码”
- c# - WordprocessingDocument:如何替换包含在一组特殊字符中的特定文本?
- ruby-on-rails - Apache 上的乘客在初始化语言运行时失败
- python-3.x - 如何在不使用函数的情况下计算包含非数字行索引和空值的多列 DataFrame 的第 25 个百分位数?
- reactjs - React Router 无法检测到匹配道具
- javascript - 尝试从 Express JS 在移动设备和 Web 之间呈现不同的视图