【问题标题】:How to use default DateTime values with SQL Server CE and Entity Framework如何在 SQL Server CE 和实体框架中使用默认 DateTime 值
【发布时间】:2014-10-09 01:35:28
【问题描述】:

为简单起见,假设我有一个名为 Widgets 的 SQL Server CE 表:

create table [Widgets] (
  [Id] int not null primary key,
  [Created] datetime not null default getdate())

在不指定 Created 列的值的情况下插入按预期工作:

insert into [Widgets] ([Id]) values (1)

在生成名为Database 的实体框架模型后,我编写以下代码:

Database db = new Database();
db.Widgets.AddObject(new Widget { Id = 2 });
db.SaveChanges();

但它引发了一个例外:An overflow occurred while converting to datetime. 我将此归结为 EF 将Created 列视为不可为空的DateTime,因此当构造一个新的Widget 时,它的@987654333 @ 属性设置为默认的 DateTime (0001-01-01 12:00:00),它超出了 SQL Server CE 的有效范围。

那么,如何让上述 C# 示例工作?我不想更改数据库架构。而且我知道我可以在Widget 构造函数中将Created 属性设置为DateTime.Now,但是从构造Widget 到实际插入数据库可能需要几分钟,这是实际的我想捕捉的时间。

更新:我尝试将StoreGeneratedPattern 设置为IdentityComputed,但它引发了一个异常:Server-generated keys and server-generated values are not supported by SQL Server Compact。默认值在 SQL Server CE 中确实有效,因此它必须是实体框架的限制。 (显然,这在 SQL Server CE 4.0 中已修复。)

【问题讨论】:

  • @TonyHopkinson 该问题的答案不能满足我的问题。如上一段所述,在构造函数中设置默认值不会调用正确的行为。构建 Widget 的时间可能与实际插入数据库的时间相差几分钟。
  • 从哲学上讲,实体是什么时候真正创建的?当一个新实体被保存到数据库中,或者当实体是在代码中创建时?有关系吗?最终用户关心吗?它是否以某种方式协助数据库管理?在我看来,用户点击“提交”或“保存”的那一刻应该是设置创建日期的那一刻。如果你能忍受这个,上面链接中的解决方案应该可以工作。
  • @乔丹。我相信那里还有其他几个答案。它还说 EF 不支持您想要的行为,尽管我不知道这是否正确。至于时间,取决于您使用时间创建的目的。

标签: c# sql-server entity-framework sql-server-ce


【解决方案1】:

看起来 DanM 的相关问题链接为我指明了更改跟踪的正确方向。以下代码将非常接近我正在寻找的行为:

public partial class Database
{
  public override int SaveChanges(SaveOptions options)
  {
    foreach(var w in this.ObjectStateManager
                         .GetObjectStateEntries(EntityState.Added)
                         .Where(e => e.Entity is Widget)
                         .Select(e => (Widget)e.Entity))
    {
      if(w.Created == default(DateTime))
        w.Created = DateTime.Now;
    }

    return base.SaveChanges(options);
  }
}

所有Widgets 的Created 值都将设置为当前日期和时间。我看到的唯一其他问题是该值是根据客户端的时钟设置的,而不是服务器的。如果您一次插入多行,时间戳会比正常插入时的时间戳稍早。

最好的解决方案是允许 SQL Server 执行其配置的操作 — 如果未提供列的值,请设置该列的值。生活吧。

【讨论】:

    【解决方案2】:

    您可以在其构造函数中设置 Widget 部分类的 Created 属性:

    public partial class Widget
        {
            public Widget()
            {
                this.Created = System.DateTime.Now;
            }
        }
    

    【讨论】:

    • 虽然这可能适用于某些实现,但不适用于这一实现。就像我在 OP 和一些 cmets 中已经说过的那样:构建 Widget 的时间可能距离它实际插入数据库的时间只有几分钟的时间。
    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多