ADO.NET Entity Framework, SQLCE and identity columns

Recently I've doing some works using MS SQL Compact Edition and for data layer ADO.NET Entity Framework was chosen. Now MS only recently added support for SQLCE in the framework, so its kind of beta inside beta. Some features are not working properly or missing, as for example, support for identity columns. While SQLCE provides support for auto-generated columns, the framework doesn't yet have it. And of course all my IDs in tables are auto-generated integer values, e.g. identity.

Of course the only option was to generate ID at client. But I didn't want to change everything to be GUID, which looks like the only option at first glance, so I was looking for a way to generate integer values. I wouldn't even think about it if I was working with SQL Server, but at the end this is SQL CE, which is not supposed to (and would not in the scope of this project) be used by different processes, so I can synchronize identity generating in-process without problems.

The solution is not something genius and its simple, but its worked for me. The only downside that I saw is that I have to add partial class for every entity in my database. Well, since I had about 15 of them, this was not a big deal. The method is added to the class that extends ObjectContext, e.g. your model class:

private static Dictionary<Type, int> _primaryKeysCache = new Dictionary<Type, int>();
public static int GenerateID<TEntity>(
Func<Model, ObjectQuery<TEntity>> table,
Func<TEntity, int> idSelector) where TEntity : EntityObject
{
lock (_primaryKeysCache)
{
int primaryKey = 0;
if (!_primaryKeysCache.TryGetValue(typeof(TEntity), out primaryKey))
{
using (Model model = Model.CreateContext())
{
primaryKey = table(model).Any() ? table(model).Max(idSelector) : 0;
}
}
primaryKey++;
_primaryKeysCache[typeof(TEntity)] = primaryKey;
return primaryKey;
}
}

In this method, "Model" is my ObjectContext and the "Model.CreateContext()" is a simple static method that returns a new instance of objects model.

Usage of this method is simple - just call it when you want to generate a new ID value. Only warning - do not do this in object's constructor, you will get endless recursion. In the example below, I have a class that stores information about single file on disk. I always create a new class using the method "New()":

partial class GenericFile
{
public static GenericFile New()
{
GenericFile ret = new GenericFile();
if (Model.ShouldGenerateID)
ret.ID = Model.GenerateID(m => m.Files, f => f.ID);
return ret;
}
}

Another thing you might note here - the static property "ShouldGenerateID" on my model. I thought to myself that probably in the future, the issue will be solved and I will not need to generate IDs myself. So I have added this boolean that currently always returns true.

Updated: June 3, 2008: For general info on how to start with SQLCE and Entity Framework, see this post in SQLCE Devs' blog

Technorati Tags: , , , , ,

posted @ Friday, May 30, 2008 6:50 PM

Print

Comments on this entry:

# re: ADO.NET Entity Framework, SQLCE and identity columns

Left by Steve at 6/3/2008 8:46 AM
Gravatar
But this means you'll have to disable the ID column to be identity right? Or can you have an identity column and still give it a value?

# re: ADO.NET Entity Framework, SQLCE and identity columns

Left by Philip Patrick at 6/3/2008 11:57 AM
Gravatar
To Steve:
Unfortunately, yes. And also you cannot simply change the identity property on column - you have to delete old column and create a new one. If you already have data in your column, you might want to write TSQL that does:
1. Create new column
2. Transfer data from old column to new one
3. Drop old column

# Oakleafblog

Left by at 7/7/2008 10:12 AM
Gravatar
Oakleafblog

# re: ADO.NET Entity Framework, SQLCE and identity columns

Left by miguel at 8/15/2008 11:31 PM
Gravatar
What would happen if two instances of an application are accessing the same SqlCe table and try to insert a record at the same time? SqlCe supports Multiple connections for foreground and background operations, therefore this escenario could occur.

# re: ADO.NET Entity Framework, SQLCE and identity columns

Left by Philip Patrick at 8/16/2008 9:35 AM
Gravatar
This is not a healthy operation, as it looks like you might lose data - e.g. the last update wins. This is according to:
http://msdn.microsoft.com/en-us/library/ms171845.aspx
"Lost updates occur when two or more transactions select the same row, and then update the row based on the value originally selected. The last update overwrites updates made by the other transactions, resulting in lost data."

Your comment:



 (will not be displayed)


 
 
 
Please add 2 and 6 and type the answer here:
 

Live Comment Preview: