Does Entity Framework 4 Code First Have Support for Identity Generators Like Nhibernate

Does Entity Framework 4 Code First have support for identity generators like NHibernate?

No, Entity framework code-first is still just nice wrapper around EFv4. There are no NHibernate like generators. If you want client side Id generator you will have to override SaveChanges in derived DbContext and implement your own logic of assigning Ids to new entities.

Edit:

Some high level example:

public class Context : DbContext
{
// Helper for example
// DO NOT USE IN REAL SCENARIOS!!!
private static int i = 0;

public DbSet<MyEntity> MyEntities { get; private set; }

public Context()
: base("connection")
{
MyEntities = Set<MyEntity>();
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<MyEntity>().HasKey(e => e.Id);
// Turn off autogeneration in database
modelBuilder.Entity<MyEntity>()
.Property(e => e.Id)
.HasDatabaseGeneratedOption(HasDatabaseGeneratedOption.None);

// Other mapping
}

public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<MyEntity>()
.Where(e => e.State == EntityState.Added))
{
// Here you have to add some logic to generate Id
// I'm using just static field
entry.Entity.Id = ++i;
}

return base.SaveChanges();
}
}

public class MyEntity
{
public int Id { get; set; }
// Other properties
}

Why does identity generator break unit of work in nHibernate? What about EF?

I will not tell you exactly why the insert is not deferred in NHibernate but I guess that NHibernate simply needs real entity identity immediately when you put it to the session.

EF doesn't use this approach but it doesn't mean that EF approach is better. First of all EF doesn't have built in support for identity generators. You can implement your own but it can be little bit challenging just because of issues NH is trying to avoid.

ORM tools implements identity map and they demand each entity to be uniquely identified. NH probably uses real identity immediately whereas EF can defer the identity definition and use some temporary key. This temporary key is used when the real identity is defined in the database - that means IDENTITY column in MS SQL Server. EF knows real identity only after inserting record to the database and querying SCOPE_IDENTIY(). When EF receives the real key it updates the entity and all its relations (FKs) to reflects the real identity.

This is also the biggest disadvantage of the approach - EF must insert every record in separate roundtrip to database to get its primary key value (EF doesn't support command batching anyway). Here you find the biggest difference with NH which is able to pregenerate identities using generators and batch those DML commands to single roundtrip to database.

Usage of temporary keys in EF has another side effects when you start using FK properties introduced in EF 4.0. Once FK properties are used you must explicitly set PK to some unique temporary value otherwise inserting two records with relations will fail with exception (you will have two entities with default key value and FK properties will not be able to define which one is a correct principal).

EF is designed to work with database generated keys whereas NH prefers application generated keys.

EF with KeyTable Sequence style PK

I guess the question is fundamentally more about whether Entity Framework can support this style of key generation, and a secondary part of the question is whether RIA Services would integrate OK with that.

It reminds me of the range of key generation strategies that are available in NHibernate.

Here's an answer here which suggests that EF does not have such full support as NHibernate 'out of the box':

Unfortunately, EF doesn't have anything very close to the POID
generators like NHibernate does, although I hear rumors that similar
capabilities will be included in the next release of EF.

from HiLO for the Entity Framework

This answer suggests that it's not too tricky to intercept a Save (specifically an insert) in RIA Services and call a SPROC to get the new ID

you only need to call stored procedure to get a value before you are
going to save the record [can put this into an] overriden
SaveChanges() in your context

see https://stackoverflow.com/a/5924487/5351 in answer to What is the best way to manually generate Primary Keys in Entity Framework 4.1 Code First

and a similar answer here... https://stackoverflow.com/a/5277642/5351

Here are some findings on possibly implementing a HiLo generator (a more robust key gen pattern) with EF:

The Hi/Lo pattern describe a mechanism for generating safe-ids on the
client side rather than the database. Safe in this context means
without collisions. This pattern is interesting for three reasons:

  • It doesn’t break the Unit of Work pattern (check  this link and this other one)
  • It doesn’t need many round-trips as the Sequence generator in other DBMS.
  • It generates human readable identifier unlike to GUID techniques.

from http://joseoncode.com/2011/03/23/hilo-for-entityframework/

Entity Framework. Column Null or Incrementing Identity

I think (if I'm getting right what you're after),

your best option is using Guid column - and most likely having to custom implement the Guid ID from the EF/C# side - so that you could keep the column 'null' also when wanted.

Closest to what you need is what's described already in this question,

Does Entity Framework 4 Code First have support for identity generators like NHibernate?

Modify PK bevor saving to the DB in EF4

This question was asked several times at Stackoverflow. Please read this response: Does Entity Framework 4 Code First have support for identity generators like NHibernate?

It solves the problem described by you. If you do not use the code first approach as in your case, then overwrite the SaveChanges method in the generated class that inherits from ObjectContext. The class DbContext is only used for Code First approach. E.g.:

public interface IEntity
{
string Id { get; set; }
}

public partial class MyEntity: IEntity
{
}

public partial class MyEntities
{
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
var generator = new IdGenerator();

foreach(var entry in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added))
{
var entity = entry.Entity as IEntity;
if (entity != null)
{
entity.Id = generator.CreateNewId();
}
}

return base.SaveChanges(options);
}
}

This example assumes, that you implement IEntity for all classes in your model (like MyEntity), which depends on a special generation for the PK and MyEntities is an ObjectContext. IdGenerator should offer your method of providing the primary key. This code also requires, that the property Id is located in the generated code.

Generate Guid on Serverside Entity Framework 5?

If you want to generate the key on the server, simply do this in code:

public class TestObject 
{
public TestObject()
{
Id = Guid.NewGuid();
}
public Guid Id { get; set; }
}

If you want the database to generate the key, then use the DatabaseGenerated attribute:

public class TestObject 
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
}

If you're after using sequential GUIDs, then there's no easy answer at the moment. Some examples which get you along the right road:

  • Generating IDs in the SaveChanges method
  • Calling your own NewGuid method
  • Use a non-EF method to change the default value for the identity field from NEWID() to NEWSEQUENTIALID()

Entity Framework Identity Increment Configuration

You cannot change the seed - EF doesn't allow that. Also changing the seed on the existing table means dropping the column and creating it again. So the answer to this part is no.

Creating scripts "is possible" but you will lost a lot of features EF is doing for you. You will probably lose:

  • Database creation - you will only get script to create tables
  • Database consistency check (EdmMetadata support)

Check this article about creating initializer for existing database which retrievs



Related Topics



Leave a reply



Submit