C# 9 - 使用 Entity Framework 更新记录的仅初始化属性
C# 9 - updating init-only properties on records with Entity Framework
C# 9 引入了 records and init-only properties 以便更容易编写不可变引用对象。
我一直在尝试转换旧的 Entity Framework 项目以使用这些功能,但我在具有仅初始化属性的不可变 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 - Init-only property or indexer can only be assigned in an object initializer
上线
usageReport.ReadyToUse = true;
我对这个错误没有任何抱怨,因为你显然不能在构造函数之外更新 init-only 属性,但我想知道是否有使用 init-only 的好方法Entity Framework.
中的属性和可变 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# 记录时解决方案完全相同。
C# 9 引入了 records and init-only properties 以便更容易编写不可变引用对象。
我一直在尝试转换旧的 Entity Framework 项目以使用这些功能,但我在具有仅初始化属性的不可变 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 - Init-only property or indexer can only be assigned in an object initializer
上线
usageReport.ReadyToUse = true;
我对这个错误没有任何抱怨,因为你显然不能在构造函数之外更新 init-only 属性,但我想知道是否有使用 init-only 的好方法Entity Framework.
中的属性和可变 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# 记录时解决方案完全相同。