I have a DateTime column in my app that gets auto calculated by SQLServer. It works great when creating the row. However, I would like to be able to updated later. I have the property marked with [DatabaseGenerated(DatabaseGeneratedOption.Computed)].
Is it possible to updated a property like that in EF?
No, with DatabaseGeneratedOption.Computed EF will never include the property in update and insert statements. In stead, it will always read its value after such statements.
If you have to update the property in client code you have no other option than removing the data annotation an make it an ordinary updateable property. You can set a default value in the owning class's constructor.
Related
I'm new to Entity Framework in C#.
I'm having one computational column in my table table1(example). I will calculate the computational column value based on the other columns value. I don't want Entity Framework to include the computational column while performing insert/update operations. How can I make the EF to avoid that particular column. But I want to set the value for that particular column manually.
I searched for the same but i couldn't able to get the answer for my question. Kindly help me and thanks in advance.
You can use the NotMapped Annotation
Code first convention dictates that every property that is of a
supported data type is represented in the database. That property can
be created dynamically and does not need to be stored. You can mark
any properties that do not map to the database with the NotMapped
annotation.
[NotMapped]
public string Something
{
get
{
return _something;
}
set
{
_something = value
}
}
Update : this is will not map to the dB, so is probably not what you are looking for
Just to make this a more complete the DatabaseGenerated Annotation, are the droids you are looking for
An important database features is the ability to have computed
properties. If you're mapping your Code First classes to tables that
contain computed columns, you don't want Entity Framework to try to
update those columns. But you do want EF to return those values from
the database after you've inserted or updated data. You can use the
DatabaseGenerated annotation to flag those properties in your class
along with the Computed enum. Other enums are None and Identity.
Which can be used with the DatabaseGeneratedOption
Computed : The database generates a value when a row is inserted or updated.
Identity : The database generates a value when a row is inserted.
None : The database does not generate values.
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
public string Something { get; set; }
As you calculate your column server side the correct way is to configure the field at the context level with:
HasComputedColumnSql for ef-core
DatabaseGeneratedAttibute for EF-6 (HasDatabaseGeneratedOption for the fluent api)
If you use NotMapped, you will not get the value from the database.
Using Entity Framework 5, Given an object messenger that exists in the database, with bit property published, in previous versions of EF I would update it like this:
using (var c = new EFContext())
{
Data.Messenger cm = new Messenger { MessageId = messageId };
c.Messengers.Attach(cm);
cm.Published = newPublishedValue;
c.SaveChanges();
}
However, using EF5, this works if newPublishedValue is true, but if newPublishedValue is false, no changes are made to the database. Likewise, this pattern will not set integer values to 0.
What's going on here?
Replacing
c.Messengers.Attach(cm);
with
c.Entry(cm).State = System.Data.EntityState.Modified;
Fixes the issue, but if EF5 won't update properties of my new Data.Messenger that are of a default struct value, doesn't that render the Attach method a bit useless?
What am I missing here?
It only worked in previous versions probably when you have used entities derived from EntityObject or POCOs with dynamic proxy change tracking. In that case the property setter is overridden with code that sets a Modified flag for this property when you assign a value (= call the setter) no matter what the old value was.
Using POCOs without dynamic change tracking proxies it doesn't work - for no version of EF - because the property setter is just an assignment of a data field in the entity class. Change tracking happens by snapshot change tracking which means that EF compares the values of a snapshot of the entity taken when you call Attach with the values the entity has when you call SaveChanges. If the values didn't change EF detects no changes and doesn't write an UPDATE statement for the property.
Attach is only for adding an entity to the context in Unchanged state. In your case you have to mark the property as Modified explicitly to ensure that it will be updated in the DB, no matter what the old value was:
c.Entry(cm).Property(x => x.Published).IsModified = true;
My table Sections (SQL Server) has ID as a primary key (int, identity) and SortIndex column (int) for sorting purposes.
The database has a trigger which sets SortIndex := ID at each INSERT. Obviously I want to change the sorting index later, by swapping the values for two rows.
I access the data using Entity Framework, all with MVC3 web application.
The problem is, Entity Framework doesn't update the value of SortIndex after I insert a new object into the table. It also caches all the data, so the following call to get all objects from this table will also give wrong SortIndex value for this object.
I tried changing StoreGeneratedPattern for this column in EDMX. This seems to be great and elegant but doesn't solve the problem.
If I set to Identity, it causes EF to properly update the value, but it becomes read only (exception thrown when trying to change). Setting it to Computed is similar, but instead of exception being thrown the values are just not written to the DB.
I can recreate the EF object every time if I need to use it after inserting an object, just by doing:
DatabaseEntities db = new DatabaseEntities()
But it seems like ugly workaround for me.
What's a solution to this problem?
Obviously something, what doesn't require me to do some action after every insert (and take a risk that it's forgotten and unnoticed) is preferred.
In short StoreGeneratedPattern means: the value is handled by the store and your application will never modify it. In such case you will get store generated value automatically after you call SaveChanges.
If you don't use StoreGeneratedPattern you will not get value and you will have to force another query execution to refresh your entity. You can for example do:
objectContext.Refresh(RefreshMode.StoreWins, yourSection);
Generally situations where you need to update values in both database through triggers and application don't play very nicely with EF (and probably also other ORM tools).
I found the answer from 'Ladislav Mrnka' being exact and marked it as accepted. Here are other workarounds, which I found while trying to find some solution. However, the solution I was looking for is in general not possible.
One of possibilities is to set StoreGeneratedPattern = Computed to let EF know, this value is calculated. And then, make a Stored Procedure to actually change the value of SortIndex. Typically it would change values in two rows (swap them), to change the sorting order. This procedure along with a trigger at INSERT gives guarantee the data stays consistent in the DB. It's not possible to create new row without proper value set in SortIndex, it's not possible to make two objects have the same value (unless stored procedure has a bug) and it's not possible to manually break the value somehow, because it's not possible to edit through EF. Looks like a great solution.
It's easily possible to have stored procedures mapped to functions in EF.
The problem is, it's now fine to enter a new row and EF properly updates data in its cache, but the cache is not updated after calling the stored procedure. Still some manual updated or refresh function is needed. Otherwise the following call to get objects sorted by SortIndex will give wrong results.
Other than that, it's possible to set MergeOption = MergeOption.OverwriteChanges for several entities, which causes EF to update data from the DB somewhat better. With this being done, it's possible to reread the object after inserting it or calling stored procedure and it will get refreshed. However, reading a collection of objects with db.Section.OrderBy(o => o.SortIndex) will still return cached results with wrong sorting order.
If anyone is interested, it's possible to make MergeOption default to something else by adding EF partial class and then partial method OnContextCreated, like here:
public partial class DatabaseEntities
{
partial void OnContextCreated()
{
Subsection.MergeOption = MergeOption.OverwriteChanges;
Section.MergeOption = MergeOption.OverwriteChanges;
Function.MergeOption = MergeOption.OverwriteChanges;
}
}
Do you know if you'll work with that column again in the same request?
I would use the context per request scenario, which usually gets you out of many problem, because a new EF context is created with every request, so you have a fresh data once per request.
With long lived context, there can grow incosistencies as you described.
Anyways the StoreGeneratedPattern setted to computed should be right. But it updates itself only when you're storing the actual entity. It's not getting updated by inserting or updating any other entity.
from http://msdn.microsoft.com/en-us/library/dd296755(v=vs.90).aspx
If you create a new entity or change an existing entity, the values of properties with StoreGeneratedPattern set to Computed are retrieved from the server when you call the SaveChanges method in your application.
If you assign a value to a property with StoreGeneratedPattern set to Computed in your application, the value will be overwritten with the server-generated value when you call the SaveChanges method.
We're using the computed value option for SQL sequenced GUID, and it's working OK.
I had a similar situation with a Sql Server Quote table with a varchar QuoteNumber column that is a non-primary unique key whose value is generated by an after-insert trigger. The trigger is used because the generated value is derived by fetching data from a foreign key table. Sql Server schema identity declarations do not allow you to pull information from other tables.
I'd like EF to treat this varchar column like an identity and do nothing to it on update and reread it after insert. EF will do so if there is a .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity) property to a non-identity column in the code it generates to configure the Entity like so (scroll right):
public QuoteConfiguration(string schema)
{
ToTable("Quote", schema);
HasKey(x => x.ID);
Property(x => x.ID).HasColumnName(#"ID").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
Property(x => x.QuoteNumber).HasColumnName(#"Quote_Number").HasColumnType("varchar").IsOptional().IsUnicode(false).HasMaxLength(64).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
}
My EF model is code first and generated by Simon Hughes' EntityFramework Reverse POCO Generator. At first, I could not figure out how to make the generator add this property to a column that is not declared as an identity in Sql Server.
Rereading the entire Quote entity after insert did not retrieve the auto-generated QuoteNumber. Then I discovered that re-reading just the QuoteNumber column after insert defeated the entity cache. But, I felt dirty doing it.
Finally, I worked with Simon Hughes to discover how to get his EF Reverse POCO to do it for me. You just extend the UpdateColumn function in your *.tt file like so:
Settings.UpdateColumn = (Column column, Table table) =>
{
if (table.Name.Equals("Quote", StringComparison.InvariantCultureIgnoreCase)
&& column.Name.Equals("Quote_Number", StringComparison.InvariantCultureIgnoreCase))
{
column.IsStoreGenerated = true;
}
}
In my SQL Server database schema I have a data table with a date field that contains a default value of
CONVERT(VARCHAR(10), GETDATE(), 111)
which is ideal for automatically inserting the date into the new record when manually entering records in to the database.
The problem I have is that when using the Entity Framework and mapping the Date field, that the Entity Framework inserts a default value of DateTime.Min when the entity is instantiated.
I cannot map the Date field to a nullable DateTime, i.e. DateTime?, nor am I able to use either CONVERT or DateTime.Now.Today in the default value of the Entity Designer as it only accepts hard-coded constant values.
I can of course explicitly set the DateTime field in C# whenever the object is created, either explicitly in code, in the constructor of a partial class, or even during the saving changes event.
Are there any other ways of achieving what I want where the default value calculation stored in the database table is actually used instead?
Create a partial class for your EntityObject, add a default constructor, and set default values in it.
public partial class YourDBObject
{
public YourDBObject()
{
this._DateField = DateTime.Now;
}
}
You can use a database trigger, which, on insertion, checks if the inserted value is DateTime.MinValue (01.01.0001) and replaces it with the calculated value you desire. This MSDN article describes how to create a trigger.
A little "flaw": with this solution you would have to store the new object to the database and read it back afterwards to update your object with the calculated value.
This is really unfortunate. The answers referencing StoreGeneratedPattern are not a true solution, that doesn't allow you to ever set the value.
All the team would have to do is something like this:
[Required]
[DefaultValue] // suggested attribute, whatever you want to call it
public DateTime Created { get; set; }
If a field is marked DefaultValue, then at EF's SQL generation time, properties with this attribute get checked if field == default(DateTime), if so, then simply omit that column from the generated code.
Just happened to cross through this issue. Entity Framework do not support default values on its own. You need to set the property StoreGeneratedPattern = Computed on the column in the Edmx file entity. The default value what you set in the Database will then precedence on what EF sets by default i.e. DateTime.Min
I just ran into this - I worked around it by setting the date (the field I needed auto generated) in the constructor of the Entity using a partial method. Whether this is Ideal or whether it works in all cases is yet to be seen, but it has fixed my problem so far.
I had a similar problem using RIA Services with the Entity Framework. I was not able to set the value in the default constructor on the client side because the entity classes that are generated there already have an empty default constructor.
The solution that I used was to implement the OnCreated partial method for the entity on the client by setting the required default value.
I think the answer provided by lazyberezovsky on another SO question is the straight forward solution to this problem Entity Framework and Default Date
The date field can be mapped to DateTime? only if the column is nullable in the database.
Link
I'm using ASP.NET with C# and trying to use linq to sql to update a data context as exhibited on the blog linked above. I created the timestamp field in the table just as stated and am using the following method:
private void updateRecord(TableName updatedRecord)
{
context db = new context();
db.TableName.Attach(updatedRecord,true);
db.SubmitChanges();
}
My question is, are you supposed to assign the timeStamp field to anything in your updatedRecord before trying to call the Attach method on your data context?
When I run this code I get the following exception: System.Data.Linq.ChangeConflictException: Row not found or changed. I update all of the fields, including the primary key of the record that I'm updating before passing the object to this update method. During debugging the TimeStamp attribute of the object shows as null. I'm not sure if it's supposed to be that way or not.
Every book and resource I have says that this is the way to do it, but none of them go into great detail about this TimeStamp attribute.
I know this is quick and easy, so if anybody knows, please let me know.
Since you say that you created the time stamp field in the table, I wonder if, in the case where this column was added later, the column properties may not be set correctly.
You may want to check the properties on your TimeStamp column in the DBML designer. Make sure that:
AutoGenerated = true
Auto-Sync = Always
Time Stamp = True
Update Check = Never
The server data type should be rowversion NOT NULL
If it is not set to be auto generated and synced always, the row version won't be returned from the insert since you haven't changed it when the insert was done. Even though this value is generated by the database the DataContext needs to know this so that it can handle it properly.
In addition, now that you have a timestamp column, UpdateCheck should be set to Never for all of the other columns.
If you have a timestamp column, then to update a record (from a vanilla object): yes, I would expect to have to assign it. Otherwise, you lose the ability to use the timestamp for optimistic concurrency checking.
The idea is you take a copy of the timestamp when you get hold of your (disconnected) object, then when you update you can use this column to verify that nobody else has edited the row.
There are two common scenarios:
1: if you are only performing a short lived operation, get the record out of the database first - make your changes to the object, and simply SumbitChanges() [all with the same data-context]. The data-context will handle concurrency for you.
2: if you are disconnecting the object (for example passing it to a client application for a while), then use something like serialization (LINQ-to-SQL objects support DataContractSerializer (optionally; you need to enable it)). So serialize the object at the server, pass it to the client - the client makes changes to their copy and passes it back. The server deserializes it and uses Attach() and SubmitChanges(). The record in memory should still have the timestamp that it had when extracted from the database, so we can perform optimistic concurrency spanning all the time the record has been disconnected.