【发布时间】:2021-01-24 15:30:16
【问题描述】:
C# 9 引入了records 和init-only properties,以便更轻松地编写不可变引用对象。
我一直在尝试将旧的实体框架项目转换为使用这些功能,但我在具有仅初始化属性的不可变 C# 记录和尝试更改底层 SQL 记录之间遇到了一些摩擦。
也许我只是在逆流而上,但是有没有一种模式可以将 C# 类定义为不可变的仅初始化记录,但仍允许更新基础 SQL 数据?
我当前的(工作)代码使用可变的类:
MyReport.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; }
}
}
MyApp.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 记录和仅初始化属性:
MyReport.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;
我没有抱怨这个错误,因为您显然无法在构造函数之外更新仅 init 属性,但我想知道是否有一种好方法可以使用 init-only 属性和可变 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 数据的更改,而不会触发大量删除和重新插入。
【问题讨论】:
-
我不确定记录实际上与批量插入的死锁问题有何关系。如果你用 poco 替换记录,它仍然会导致问题吗?
-
你能解释一下你为什么要首先使用记录吗?
-
您写道:C# 9 引入了记录和仅初始化属性,以便更轻松地编写 不可变 引用对象。,然后您编写了 如果有一个很好的方法来处理仅初始化属性和 可变 Entity Framework 中的 SQL 数据 - 你能看到这些语句的冲突吗?
-
@Fabio - 是的,我理解冲突,这就是为什么我基本上在寻找一种明智的方法来解决它:-)。我想我想将内存中的记录视为底层业务对象的不可变“快照”,但同时能够用新的“快照”更新存储中的底层对象。我认为问题在于 Entity Framework 并非旨在以这种方式工作 - 它似乎期望您的实体是可变的 poco 引用(mutable 记录也可以正常工作,顺便说一句),它跟踪更改然后适用于底层存储。
-
没有什么能阻止您使
ReadyToUse可变并写入public bool ReadyToUse { get; set; }。另一方面,为什么要保存一个不完整的Report对象根本?如果您不保存不完整的对象,则不需要ReadyToUse标志。你的代码想做什么?
标签: c# entity-framework c#-9.0