简体   繁体   中英

How to insert identity value in Oracle using Entity Framework using a sequence

In an Oracle database, that has an ID column defined as a number:

在此处输入图片说明

...and a corresponding sequence for the table...:

在此处输入图片说明

How do I make sure the ID column gets the next value in the sequence?

using (var db = new MyOracleDb()){
    var user= new User(){ first_name = 'Abe', last_name = 'Lincoln'};
    //Do something here with the sequence and set the ID?
    db.User.Add(user);
    db.SaveChanges();
}

I am using the latest Oracle.ManagedDataAccess and Oracle.ManagedDataAccess.EntityFramework + EF6x.

This is not an EF issue, as there is no auto increment in oracle. You will have to either get the sequence value manually, or create a trigger to set it for you.

Update

In order to get the sequence value you have two options - either create a stored procedure, that returns the value - or create a .Net function ( doesn't really have to be in a function, it's just simpler) that calls raw SQL like this:

Database.SqlQuery<int>("SELECT SEQ_SOMESEQ.NEXTVAL FROM dual");

I personally had many issues with oracle functions and EF, so I would go with the raw sql.

I've created an interface:

public interface IHasSequencer
{
    decimal Id { get; set; }
    string GetSequenser();
}

Then implemented it in my model:

[Table("CLN_CLIENTS")]
public class ClnClient : IHasSequencer
{
    public string GetSequenser()
    {
        return "SEQ_CLN_CLIENTS";
    }

    [Key, Column("ID")]
    public decimal Id { get; set; }

    [Column("FIRSTNAME")]
    public string FirstName { get; set; }

    [Column("LASTNAME")]
    public string LastName { get; set; }

    [Column("MIDDLENAME")]
    public string MiidleName { get; set; }
}

And added some MAGIC overriding SaveChanges() method in my DbContext:

 public override int SaveChanges()
    {
        var addedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Added);

        foreach (DbEntityEntry entry in addedEntries)
        {
            if (entry.Entity is IHasSequencer)
            {
                var sequencerEntity = entry.Entity as IHasSequencer;
                var nextSeqVal = Database.SqlQuery<Int64>("SELECT " + sequencerEntity.GetSequenser() + ".NEXTVAL FROM DUAL").First();
                sequencerEntity.Id = nextSeqVal;
            }
        }
        return base.SaveChanges();
    }

That's it! Now models that need sequenceer ID value must implement small interface.

Just FYI, With Entity Framework I had issues with unique constraints. For future readers if you're still having unique constraint issues. Please make sure you change the property "StoreGeneratedPattern" to your requirement.

For me I was adding MAX(ID) + 1 and had StoreGeneratedPattern set as Identity which started to work fine but after sometime break the whole program by throwing the same unique constraint issue, which when I checked database was definitely not the case. It was something that most developers didn't pay attention to.

I've changed it to "None" So I have control over it to what to add rather than entity framework breaking it after every few days. Entity Framework Property Picture

If you create the trigger on Oracle's side you don't have to worry about it on your code. It works as if it did have an Identity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM