为什么 C# EF Core 会删除使用块之间的值?
Why does C# EF Core remove values between using blocks?
编辑:答案很简单,我错过了 属性 {get;在我的时间戳上设置},因此 EF Core 会忽略映射。但如果您愿意,请继续阅读。
我正在使用 C# EF Core 的 InMemoryDatabase 为我的应用程序进行单元测试。但是,对于一组特定的测试,我遇到了一个奇怪的错误,当我稍后引用它们时,某些实体上的 DateTime 被重置为默认值 [1/1/0001 12:00:00 AM]
。
这是正在创建并添加到上下文中的 POCO 对象:
public class Meter
{
[Key]
public long Id { get; set; }
public DateTime Timestamp;
public int Change { get; set; }
}
这里是它被添加到 DbContext 的地方:
options = new DbContextOptionsBuilder().UseInMemoryDatabase("TestDB");
using (var db = new CustomContext(options))
{
for (int i = 0; i < 10; i++)
{
var meter = new Meter {Timestamp = new DateTime(2019, 1, 20), Change = i};
db.Meters.Add(meter);
}
db.SaveChanges();
}
如果我在 db.SaveChanges()
行之后的测试期间断点,我可以看到仪表已添加到 Meters DbSet 并且它们具有正确的时间戳日期时间(即 [1/20/2019 12:00:00 AM]
).
尽管如此,当我稍后像这样引用上下文时:
using (var db = new CustomContext(options)) //Same options as I used before
{
var times = db.Meters.Select(m => m.Timestamp);
}
如果我在此行断点,db.Meters 中的每个仪表都已设置为 [1/1/0001 12:00:00 AM]
的默认开始日期时间。但是,Change
属性 仍按预期保持原始 int 值。
这让我很震惊,我已经尝试了几种方法来解决这个问题。我尝试在添加和查询之间添加一个中间步骤,我将遍历每个仪表并更新时间戳,保存更改,然后再查询——但它仍然失败了!我尝试了 DateTime? Timestamp
并且只是将时间设置为空,我还尝试添加 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
因为这在使用我的 Npgsql 数据库时有所帮助并告诉它使用 CURRENT_TIMESTAMP 如果时间戳是曾经设置为空。我意识到我没有告诉 InMemoryDatabase 如何处理空值,但我也从来没有给它空值,所以给出了什么?
是否需要设置一些设置以防止 InMemoryDatabase 在设置值后触及这些值?
此问题与 InMemory 数据库没有任何共同之处。
原因是您实体中的一个小错误:
public DateTime Timestamp;
Timestamp
是一个 字段 ,因此未映射且未存储。在使用用于添加实体的上下文时,更改跟踪器 returns 原始实例,这就是为什么您会看到已设置的值。但是一旦你创建了一个新的上下文,查询就会创建新的对象,当然没有映射的字段有默认值。
干脆属性
public DateTime Timestamp { get; set; }
编辑:答案很简单,我错过了 属性 {get;在我的时间戳上设置},因此 EF Core 会忽略映射。但如果您愿意,请继续阅读。
我正在使用 C# EF Core 的 InMemoryDatabase 为我的应用程序进行单元测试。但是,对于一组特定的测试,我遇到了一个奇怪的错误,当我稍后引用它们时,某些实体上的 DateTime 被重置为默认值 [1/1/0001 12:00:00 AM]
。
这是正在创建并添加到上下文中的 POCO 对象:
public class Meter
{
[Key]
public long Id { get; set; }
public DateTime Timestamp;
public int Change { get; set; }
}
这里是它被添加到 DbContext 的地方:
options = new DbContextOptionsBuilder().UseInMemoryDatabase("TestDB");
using (var db = new CustomContext(options))
{
for (int i = 0; i < 10; i++)
{
var meter = new Meter {Timestamp = new DateTime(2019, 1, 20), Change = i};
db.Meters.Add(meter);
}
db.SaveChanges();
}
如果我在 db.SaveChanges()
行之后的测试期间断点,我可以看到仪表已添加到 Meters DbSet 并且它们具有正确的时间戳日期时间(即 [1/20/2019 12:00:00 AM]
).
尽管如此,当我稍后像这样引用上下文时:
using (var db = new CustomContext(options)) //Same options as I used before
{
var times = db.Meters.Select(m => m.Timestamp);
}
如果我在此行断点,db.Meters 中的每个仪表都已设置为 [1/1/0001 12:00:00 AM]
的默认开始日期时间。但是,Change
属性 仍按预期保持原始 int 值。
这让我很震惊,我已经尝试了几种方法来解决这个问题。我尝试在添加和查询之间添加一个中间步骤,我将遍历每个仪表并更新时间戳,保存更改,然后再查询——但它仍然失败了!我尝试了 DateTime? Timestamp
并且只是将时间设置为空,我还尝试添加 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
因为这在使用我的 Npgsql 数据库时有所帮助并告诉它使用 CURRENT_TIMESTAMP 如果时间戳是曾经设置为空。我意识到我没有告诉 InMemoryDatabase 如何处理空值,但我也从来没有给它空值,所以给出了什么?
是否需要设置一些设置以防止 InMemoryDatabase 在设置值后触及这些值?
此问题与 InMemory 数据库没有任何共同之处。
原因是您实体中的一个小错误:
public DateTime Timestamp;
Timestamp
是一个 字段 ,因此未映射且未存储。在使用用于添加实体的上下文时,更改跟踪器 returns 原始实例,这就是为什么您会看到已设置的值。但是一旦你创建了一个新的上下文,查询就会创建新的对象,当然没有映射的字段有默认值。
干脆属性
public DateTime Timestamp { get; set; }