I've found two ways of concurrency checking for my entities in EF 4.1:
TimeStamp attribute for byte array
ConcurrencyCheck attribute for another types
The first one is very simple. You just mark byte array property as TimeStamp, create additional column in database and voila...
I've got a problem with the second method. Enity Framework has started generate sql script for concurrency check, when I marked the LastUpdateDate property.
Property:
[ConcurrencyCheck]
public DateTime LastUpdateDate { get; set; }
Sql:
select
...
where (([Id] = #3) and ([LastUpdateDate] = #4))
...
#4='value'
But EF does not generate sql script for updating the value of LastUpdateDate?
Is it possible to say EF to update the LastUpdateDate after concurrency checking without triggers or something like this?
And the second question:
What is the best practice of using concurrency checking in EF when you have something like LastUpdateDate property(property will be displayed in UI)? Is it better to check concurency using LastUpdateDate and avoid creating of addtional column for TimeStamp in your tables or
create additional TimeStamp property and renounce of the using DateTime property for concurrency checking?
Have you tried to use a rowversion (timestamp) instead of the DateTime datatype to check for concurency?
I would use the timestamp, because you are sure that the system will update it for you. Further more the value will be very precice.
The following blog posts will give you more information about how to map a timestamp.
The first one shows how to use the timestamp as a concurrency check.
Code First Optimistic Concurrency with Fluent Assertions
Round tripping a timestamp field with EF4.1 Code First and MVC 3
Related
I am working on a legacy web app which implements model first(edmx file) approach using Entity Framework.
I need to implement optimistic concurrency, so I have added this field as following:
and inside the database has been created as binary(8) type.
But when I try to update the entity is getting updated but the VersionRow values is not updated(no new value generated).
P.S
When I added the column I have binded default value as 0x0000000000000000 because it does not allow null values.
Yea I solved it this way:
1) I changed the type of RowVersion column from Binary(10) into timestamp inside SqlServer.
2) In the property details inside the .edmx file I have put the property StoreGeneratedPattern of the property RowVersion as Computed.
Computed it means that a new value is generated on insert and update.
Now it became as following:
I have a question about Postgres and GenerationType.Identity vs Sequence
In this example...
#Id
#SequenceGenerator(name="mytable_id_seq",
sequenceName="mytable_id_seq",
allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="mytable_id_seq")
I understand that I am specifying a Postgres sequence to use via annotations.
However, I have an id column defined with the 'serial' type, I have read that I can simply use GenerationType.IDENTITY and it will automatically generate a db sequence and use it to auto increment.
If that's the case, I don't see an advantage to using the SEQUENCE annotations unless you are using an integer for an id or have some specific reason to use another sequence you have created. IDENTITY is alot less code and potentially makes it portable across databases.
Is there something I'm missing?
Thanks in advance for the feedback.
If you have a column of type SERIAL, it will be sufficient to annotate your id field with:
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
This is telling Hibernate that the database will be looking after the generation of the id column. How the database implements the auto-generation is vendor specific and can be considered "transparent" to Hibernate. Hibernate just needs to know that after the row is inserted, there will be an id value for that row that it can retrieve somehow.
If using GenerationType.SEQUENCE, you are telling Hibernate that the database is not automatically populating the id column. Instead, it is Hibernate's responsibility to get the next sequence value from the specified sequence and use that as the id value when inserting the row. So Hibernate is generating and inserting the id.
In the case of Postgres, it happens that defining a SERIAL column is implemented by creating a sequence and using it as a default column value. But it is the database that is populating the id field so using GenerationType.IDENTITY tells Hibernate that the database is handling id generation.
These references may help:
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators
https://www.postgresql.org/docs/8.1/static/datatype.html#DATATYPE-SERIAL
From "Pro JPA2" book:
"Another difference, hinted at earlier, between using IDENTITY and other id generation strategies is that the identifier will not be accessible until after the insert has occurred. Although no guarantee is made about the accessibility of the identifier before the transaction has completed, it is at least possible for other types of generation to eagerly allocate the identifier. But when using identity, it is the action of inserting that causes the identifier to be generated. It would be impossible for the identifier to be available before the entity is inserted into the database, and because insertion of entities is most often deferred until commit time, the identifier would not be available until after the transaction has been committed."
I think it can be helpful if you are using the same sequence for more than one table (for example you want a unique identifier for many types of bills) ... also If you want to keep track of the sequence away from the auto generated key
You can find here the solution of updating the PostgreSQL table creation accordingly, in order to work with the GenerationType.IDENTITY option.
We have a db table that has the following columns.
WidgetId (PK)
WidgetName
WidgetCreatedOn
WidgetLastUpdatedOn
We have stored procedures that handle the update/delete/insert on the Widget table.
The Insert stored proc takes just the WidgetName as the parameter e.g.
exec Widget_Insert #WidgetName='Foo Widget'
Then the stored procedure puts the dates in for the WidgetCreatedOn WidgetLastUpdatedOn itself.
The Widget object has the same properties as the table e.g.
WidgetId (Key)
WidgetName
WidgetCreatedOn
WidgetLastUpdatedOn
Is it possible to tell the MapToStoredProcedures to ignore specific properties e.g.
modelBuilder.Entity<Widget>()
.MapToStoredProcedures(s =>
s.Insert(i => i.HasName("Widget_Insert")
.Parameter(a => a.WidgetName, "WidgetName")
.Parameter(a => a.WidgetCreatedOn, **dont map it**)
.Parameter(a => a.WidgetLastUpdatedOn, **dont map it**)));
We are doing Code-First
While there might be a way to manually change the MapToStoredProcedures configuration to do this, I have not uncovered it yet. Having said that, there is a way to accomplish this which I assume is how EF expects you to do things.
In your model mapping, specifying a DatabaseGeneratedOption of Identity or Computed will prevent that property from being sent to the insert proc.
If you think about it, this makes some sense. An insert proc will take as much information from the model as possible to do the insert. But an Identity/Computed property is one for which you're saying the DB will provide the data instead so it won't look to the model for that data.
A couple of things to note with this approach. EF will expect those Identity/Computed fields to come back from the proc so you'll need a select after the insert (filtering on SCOPE_IDENTITY() in sql server). EF also assumes that Identity fields won't come back as null, so those have to be Computed even if you don't intend them to be updated later.
If none of that seems palatable, the way to do this kind of thing in EF5 (and is a bit more flexible) is to override SaveChanges on the context and call the proc when the type is Widget and is EntityState.Added. Or you could throw an exception instead to force devs to call the proc on their own vs using EF's DBSet Add method.
Any properties that don't need to be passed to mapped stored procedures (ever) can be marked as computed. Just add the attribute [DatabaseGenerated(DatabaseGeneratedOption.Computed)] in front of your property definitions. The proc MUST return a result set with all the "computed" values after your procedure runs, or else there will be optimistic concurrency errors. A Select * from where should be fine.
If your classes are generated, you can make a partial class to keep all these attributes safe.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MyEfNamespace
{
[MetadataType(typeof(MetaData))]
public partial class Widget
{
public class MetaData
{
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public System.DateTime WidgetCreatedOn;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public System.DateTime WidgetLastUpdatedOn;
...
}
}
}
I have a SalesOrder table with columns for ID and OrderID. ID is an auto-generated int. OrderID is a non-nullable string with a max length of 20, and we use it to store the customer's order number for reference.
After adding my new SalesOrder and calling SaveChanges, I get the following error:
Cannot insert the value NULL into column 'OrderID', table 'SalesOrder'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Problem is, the object that I'm saving actually does have an OrderID! It's almost like it's trying to save the entity first before it saves all the values. Is this how EF handles things?
My setup is EF4.1, using an EDMX model-first approach. StoreGeneratedPattern is set to None. Default Value is currently set to (None) but I've tried various values. Entity Key is False, since it's not part of the key. I've also tried deleting the SalesOrder entity and regenerating it from the database.
I would also like to see your code...I had similar problems when filling objects in a loop then saving them with savechanges. I thought all the fields were populated, but they were not.
I'd have to see your code that executes before the save changes before I can offer anything really helpful.
If your problem is like mine and you are calling savechanges after using an iterator to populate your objects, then you can find the bad data by moving savechanges into the iterator so that it is called with each iteration...but this is all hypothetical guesswork without seeing your code...
This is a follow-up to an earlier question I posted on EF4 entity keys with SQL Compact. SQL Compact doesn't allow server-generated identity keys, so I am left with creating my own keys as objects are added to the ObjectContext. My first choice would be an integer key, and the previous answer linked to a blog post that shows an extension method that uses the Max operator with a selector expression to find the next available key:
public static TResult NextId<TSource, TResult>(this ObjectSet<TSource> table, Expression<Func<TSource, TResult>> selector)
where TSource : class
{
TResult lastId = table.Any() ? table.Max(selector) : default(TResult);
if (lastId is int)
{
lastId = (TResult)(object)(((int)(object)lastId) + 1);
}
return lastId;
}
Here's my take on the extension method: It will work fine if the ObjectContext that I am working with has an unfiltered entity set. In that case, the ObjectContext will contain all rows from the data table, and I will get an accurate result. But if the entity set is the result of a query filter, the method will return the last entity key in the filtered entity set, which will not necessarily be the last key in the data table. So I think the extension method won't really work.
At this point, the obvious solution seems to be to simply use a GUID as the entity key. That way, I only need to call Guid.NewGuid() method to set the ID property before I add a new entity to my ObjectContext.
Here is my question: Is there a simple way of getting the last primary key in the data store from EF4 (without having to create a second ObjectContext for that purpose)? Any other reason not to take the easy way out and simply use a GUID? Thanks for your help.
I ended up going with a GUID.
The size/performance issues aren't
critical (or even noticeable) with SQL Compact, since
it is a local, single-user system.
It's not like the app will be
managing an airline reservation
system.
And at least at this point, there
seems to be no way around the "no
server-generated keys" limitation of
the SQL Compact/EF4 stack. If someone has a clever hack, I'm still open to it.
That doesn't mean I would take the same approach in SQL Server or SQL Express. I still have a definite preference for integer keys, and SQL Compact's bigger siblings allow them in conjunction with EF4.
Use a Guid. AutoIncrement is not supported on Compact Framework with Entity Framework.
Also, if you ever want to create a application which uses multiple data sources, int PK's are going to fall apart on you very, very quickly.
With Guid's, you can juse call Guid.NewGuid() to get a new key.
With int's, you have to hit the database to get a valid key.
If you store data in multiple databases, int PK's will cause conflicts.
What I've done for SQL CE before, and I assume we have a single application accessing the database, is to calculate the MAX value on startup and put it in a static variable. You can now hand out sequential values easily and you can make the code to generate them thread safe very easily.
One reason to avoid Guids would be size = memory and storage space consumption.
You could also query SQL Compact metadata like so:
SELECT AUTOINC_NEXT FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Categories' AND AUTOINC_NEXT IS NOT NULL