Entity Framework 4 and SYSUTCDATETIME () - c#

I have a Table in my DataBase (MS SQL 2008) with a default value for a column SYSUTCDATETIME ().
The Idea is to automatically add Date and Time as soon as a new record is Created.
I create my Conceptual Model using EF4, and I have created an ASP.PAGE with a DetailsView Control in INSERT MODE.
My problems:
When I create a new Record. EF is not able to insert the actual Date and Time value but it inserts instead this value 0001-01-01 00:00:00.00.
I suppose the EF is not able to use SYSUTCDATETIME () defined in my DataBase
Any idea how to solve it? Thanks
Here my SQL script
CREATE TABLE dbo.CmsAdvertisers
(
AdvertiserId int NOT NULL IDENTITY
CONSTRAINT PK_CmsAdvertisers_AdvertiserId PRIMARY KEY,
DateCreated dateTime2(2) NOT NULL
CONSTRAINT DF_CmsAdvertisers_DateCreated DEFAULT sysutcdatetime (),
ReferenceAdvertiser varchar(64) NOT NULL,
NoteInternal nvarchar(256) NOT NULL
CONSTRAINT DF_CmsAdvertisers_NoteInternal DEFAULT ''
);
My Temporary solution:
Please guys help me on this
e.Values["DateCreated"] = DateTime.UtcNow;
More info here:
http://msdn.microsoft.com/en-us/library/bb387157.aspx
How to use the default Entity Framework and default date values
http://msdn.microsoft.com/en-us/library/dd296755.aspx

The problem is that EF doesn't know about that default value so it sends .NET default value to database. It is possible to force EF to use default value from DB but you must manually modify EDMX file (XML not designer). You must find column definition in SSDL part of EDMX and add StoreGeneratedPattern="Computed" attribute. You also must the same in CSDL part (this can be done in designer).
This setting will have several problems. First of all each update from database will delete your changes in SSDL. Also each insert and update will trigger select which will requery value from this column (because EF thinks that it is computed every time).

In your ASP .NET page when you create the record are you actually adding a value for the DateCreated value. I see that you are doing that now, which is what you needed to be doing in the first place.
So I would guess what was happening earlier is that you were creating your new record but not setting a value for the DateCreated Field. But since a DateTime has a default value of 0001-01-01 00:00:00.00 is why you were getting that behavior.
The default value would only work for the case where you insert a row but provide no indication of what to do with the DateCreated field. But the way that EF works it is always going to provide a value for this (unless you write your own insert query to override the generated ones).
You will also be potentially changing the value any time that you update the record as EF won't know what to do with it.

Related

DatabaseGeneratedOption: Identity vs. Computed

I am trying to understand the (functional) difference between the two DatabaseGeneratedOption's in Entity Framework (code first):
DatabaseGeneratedOption.Identity
DatebaseGeneratedOption.Computed
I have read the documentation, but I do not understand the functional difference between the two.
The option Identity is described as The database generates a value when a row is inserted. But I cannot update the value later if I try I get an exception saying that I cannot modify a column with Identity pattern.
The option Computed is described as The database generates a value when a row is inserted or updated. However, this is just what you tell Entity Framework, so far I have not been able to achieve this, without SQL triggers. If I try to update the value, nothing happens (Entity Framework refuses to overwrite the existing value).
So what I am left with, is two functionally identical options. I can have a default value in my SQL table, which will be applied on the insert. And I cannot update this value afterward (using Entity Framework). So where in lies the difference in how they should be used?
A computed column contains a value that is computed (hence the name) when the record is requested.
A computed column can be composed of other column values, constants and function return values.
You could for example create a computed column for an invoice expiry date:
CREATE TABLE Invoice
(
InvoiceDate DATETIME NOT NULL,
ExpiryDate AS DATEADD(DAY, 30, InvoiceDate)
)
Now if you mark this column as computed in Entity Framework, it will refuse any updates to that column, because it'll know the database won't support that.
So the documentation for that attribute is incorrect or incomplete.
A column marked as Identity will use the database-specific syntax to generate a primary key for the given table when inserting a record, being IDENTITY() in MSSQL and AUTO_INCREMENT for MySQL. A computed column will simply be marked as read-only, and you'll have to provide your own implementation (either in the database or in your migration file) to specify the computation (see How to add computed column using migrations in code first?).

Entity Framework not claiming datetime.now is null

Here is my code:
UVCUpdate update = new UVCUpdate();
update.CurrentDate = DateTime.Now;
_context.UVCUpdates.Add(update);
_context.SaveChanges();
Now I am getting an inner exception though saying this:
Cannot insert the value NULL into column 'CurrentDate', table 'bLinked.dbo.BlackbookUpdateUVC'; column does not allow nulls. INSERT fails.
If I output the DateTime.Now just before this code it outputs:
9/15/2016 7:26:35 PM
My data type for CurrentDate in the db is set to datetime and in the class it is set to DateTime. Neither allow for nulls, but DateTime.Now should not be null right?
It almost always happens when there is mismatch between so called "store generated pattern" between EF model and database. If model column has store generated pattern of Identity or Computed - that means EF will be sure those values will be automatically provided by database on insert or update, and there is no need to include them in INSERT or UPDATE statements. Missing values will have default NULL value, and if this column is non-nullable in database at the same time, and is not really computed or identity - you have the error in question.
I am sorry guys, I feel like an idiot. Thank you to Leopard.
I went to get the UVCUpdate class to show him and realized that when I copied that class from another class I accidentally left [DatabaseGenerated(DatabaseGeneratedOption.Identity)] in the class for the CurrentDate. So it was likely attempting to send a null value to the SQL so the SQL would create an ID, but the field was set to not allow nulls. CurrentDate was not supposed to be an ID so I removed that and now it works...

How does Entity Framework handle Default constraints in the database table?

I am working on code which I cannot run until it's finished, as it is a long and tedious process to go through. I have been tasked to add a new table to the existing database, update the .edmx of the model and write a method to add new rows to the table through c# backend code.
In my situation, I have 2 default constraints on my table
SomeTable
------------
ID INT IDENTITY (1,1) PRIMARY KEY CLUSTERED,
SomeDate DATETIME2 NOT NULL DEFAULT GETDATE(),
SomeOtherField VARCHAR(1024) NOT NULL DEFAULT ''
Using the .edmx model of this table, I set SomeDate's StoreGeneratedPattern to Computed. I also manually double-checked it in the SSDL to ensure the computed StoreGeneratedPattern attribute was on the SomeDate Field in the SomeTable entity.
As far as I know, and are unsure of, when I have a the following code
public void AddSomeRow(...)
{
SomeDbContext context = new SomeDbContext;
var table = new SomeTable { SomeOtherField = "Value" };
context.SomeTables.Add(table);
context.SaveChanges();
}
I believe the SomeDate Field will be set to it's default constraint (because it hasn't been populated in the entity). Is this true?
Doing the same steps listed above for SomeOtherField, can I still manually give it a value (the value appearing into that field instead of the Default Constraint) or omit it (The default constraint will be set into that field)?
This question was hard to explain, I apologize if it doesn't make sense
The StoreGeneratedPattern implies that the value is always generated by the DB, so that you're not allowed to modify it. I.e it only makes sense for DB computed columns.
At least until EF 6.1 there is no direct way to support DB defaults. The only thing that you can do is move the default values out of the DB and generate them in the model (or code first) side. You'll find some work-aounds but they're not safe for some cases (specially for N-tier apps).

problems with timestamp and concurrency

I am using EF 4.0 and I have in my database a table with a timestamp field because I want to control the concurrency in this table.
Then, I created my edmx and I generated the POCO classes with the template DBContext.
The first try that I do is, in the edmx, in the timestamp field, I set stored generated pattern to none. Then in my code I do:
myContext.MyTable.Attach(myEntity);
myContext.Entry<MyTable>(myEntity).Property(p => p.AnyFieldNoTimestamp).IsModified = true;
myContext.SaveChanges();
This give me an exception that says that is not possible to update a timestamp column.
If I have I only marked a field to modified, and this field is not the timestamp, why I get this error?
Then I try to set the propery stored generated pattern in the edmx to Indentity.
really I have a transaction and two saveChanges. In this second try, the first savechanges does not give any error but in the second savechanges I get the excepcion 0 rows affected, because it seem that the timestamp of the entity has changed from the first savechanges to the second, so in the concurrency control I get this excepction.
So I would like to know how can I use a timestamp field inside a transaction and two save chages.
Thanks.
I try to use the set Computed and in this case works correctly.

Using SqlServer uniqueidentifier/updated date columns with Linq to Sql - Best Approach

Rightly or wrongly, I am using unique identifier as a Primary Key for tables in my sqlserver database. I have generated a model using linq to sql (c#), however where in the case of an identity column linq to sql generates a unique key on inserting a new record for guid /uniqueidentifier the default value of 00000000-0000-0000-0000-000000000000.
I know that I can set the guid in my code: in the linq to sql model or elsewhere, or there is the default value in creating the sql server table (though this is overridden by the value generated in the code). But where is best to put generate this key, noting that my tables are always going to change as my solution develops and therefore I shall regenerate my Linq to Sql model when it does.
Does the same solution apply for a column to hold current datetime (of the insert), which would be updated with each update?
As you noted in you own post you can use the extensibility methods. Adding to your post you can look at the partial methods created in the datacontext for inserting and updating of each table. Example with a table called "test" and a "changeDate"-column:
partial void InsertTest(Test instance)
{
instance.idCol = System.Guid.NewGuid();
this.ExecuteDynamicInsert(instance);
}
partial void UpdateTest(Test instance)
{
instance.changeDate = DateTime.Now;
this.ExecuteDynamicUpdate(instance);
}
Thanks, I've tried this out and it seems to work OK.
I have another approach, which I think I shall use for guids: sqlserver default value to newid(), then in linqtosql set auto generated value property to true. This has to be done on each generation of the model, but this is fairly simple.
There's two things you can do:
either just generate the GUID in your C# client side code and use that value
create a DEFAULT constraint on the GUID column in SQL Server that defaults to newid() for the column - the SQL Server will make SURE to always add a default - unless you specify a value yourself
As for the self-updating date/time columns - here you probably have to use either client-side logic to do that, or if you want to do it on SQL Server, you'll have to write a trigger. That's really the only way to update a specific column everytime the row gets updated - there's no "autoupdate" constraint or anything like this (and the default constraint only work on INSERTs, not updates).
Something like this might work:
CREATE TRIGGER TRG_UpdateDateTimestamp
ON (your table name)
AFTER UPDATE
AS
IF NOT UPDATE(DateTimeStamp)
BEGIN
UPDATE (yourtablename)
SET DateTimeStamp = GETDATE()
WHERE EXISTS (SELECT * FROM inserted AS i
WHERE i.OID = (yourtable).OID)
END
Marc

Categories