3

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

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列视为 non-nullable的事实,DateTime因此当Widget构造一个新列时,它的Created属性设置为默认值DateTime(0001-01-01 12:00:00 ),这超出了 SQL Server CE 的有效范围。

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

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

4

2 回答 2

2

看起来 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 执行其配置的操作 — 如果未提供,则设置列的值。这就是生活。

于 2012-04-27T16:41:59.977 回答
1

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

public partial class Widget
    {
        public Widget()
        {
            this.Created = System.DateTime.Now;
        }
    }
于 2012-04-27T04:00:59.117 回答