Reputation: 6088
For simplicity's sake, let's say I have a SQL Server CE table called Widgets
:
create table [Widgets] (
[Id] int not null primary key,
[Created] datetime not null default getdate())
Inserting without specifying a value for the Created
column works as expected:
insert into [Widgets] ([Id]) values (1)
After generating an Entity Framework model called Database
, I write following code:
Database db = new Database();
db.Widgets.AddObject(new Widget { Id = 2 });
db.SaveChanges();
But it raises an exception: An overflow occurred while converting to datetime.
I tracked this down to the fact that EF sees the Created
column as a non-nullable DateTime
, and so when a new Widget
is constructed, its Created
property is set to the default DateTime
(0001-01-01 12:00:00), which is outside of the valid range for SQL Server CE.
So, how do I get the above sample of C# to work? I'd prefer not to change the database schema. And I know I could set the Created
property to DateTime.Now
in the Widget
constructor, but it may take a few minutes from the time a Widget
is constructed until its actually inserted into the database, which is that actual time I want to capture.
Update: I tried setting StoreGeneratedPattern
to Identity
and Computed
, but it raises an exception: Server-generated keys and server-generated values are not supported by SQL Server Compact
. Default values do work in SQL Server CE, so it must be a limitation of Entity Framework. (Apparently this is fixed in SQL Server CE 4.0.)
Upvotes: 3
Views: 5314
Reputation: 6088
Looks like DanM's related question link pointed me in the right direction toward change tracking. The following code will get pretty close to the behavior I'm looking for:
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);
}
}
All of the Widget
s' Created
values will be set to the current date and time. The only other issues I see is that the value is set according to the client's clock, not the server's. And if you're inserting many rows at once, the timestamps will be a little ahead of what they would be with a normal insert.
The best solution would allow SQL Server to do what it's configured to do—set the value of the column if not provided. C'est la vie.
Upvotes: 2
Reputation: 1506
You could set the Created property of the Widget partial class in its constructor:
public partial class Widget
{
public Widget()
{
this.Created = System.DateTime.Now;
}
}
Upvotes: 1