Devart.Data.Oracle.EFCore - How to use sequence to set PK column value? Devart.Data.Oracle.EFCore - How to use sequence to set PK column value? oracle oracle

Devart.Data.Oracle.EFCore - How to use sequence to set PK column value?


Ok, I have solution. It seems we need to use ValueGenerator. My implementation below.

Mapping

entity.Property(e => e.Id)      .ForOracleHasColumnName("ID")      .IsRequired()      .ValueGeneratedOnAdd()      .HasValueGenerator((_, __) => new SequenceValueGenerator(_defaultSchema, "SEQ_FOOS"));

SequenceValueGenerator (please note that ValueGenerator is EF Core type)

internal class SequenceValueGenerator : ValueGenerator<int>{    private string _schema;    private string _sequenceName;    public SequenceValueGenerator(string schema, string sequenceName)    {        _schema = schema;        _sequenceName = sequenceName;    }    public override bool GeneratesTemporaryValues => false;    public override int Next(EntityEntry entry)    {        using (var command = entry.Context.Database.GetDbConnection().CreateCommand())        {            command.CommandText = $"SELECT {_schema}.{_sequenceName}.NEXTVAL FROM DUAL";            entry.Context.Database.OpenConnection();            using (var reader = command.ExecuteReader())            {                reader.Read();                return reader.GetInt32(0);            }        }    }}

It seems to work as I needed.


Mapping:

private void FooMapping(ModelBuilder modelBuilder){    //modelBuilder.HasSequence<int>("SEQ_FOOS", schema: "SCHEMA")    // .StartsAt(1)    // .IncrementsBy(1);    modelBuilder.Entity<Foo>(entity =>    {        entity.ForOracleToTable("FOOS");        entity.HasKey(e => e.Id);        //entity.Property(e => e.Id).ForOracleHasColumnName("ID").IsRequired().ForOracleHasDefaultValueSql("SELECT SEQ_FOO.NEXTVAL FROM DUAL");        entity.Property(e => e.Value).HasColumnName("VALUE");    });}

Code:

    // https://www.devart.com/dotconnect/oracle/docs/?dbmonitor.html    var monitor = new OracleMonitor() { IsActive = true };    using (var dbContext = new FooModel())    {        dbContext.Database.EnsureDeleted();        dbContext.Database.EnsureCreated();        var foo = new Foo()        {            Value = 5        };        dbContext.Foos.Add(foo);        dbContext.SaveChanges();    }

Check SQL generated in dbMonitor. Is that what you need?


Did not figure this out. I have similar problem on Oracle 18C - I need to fill PK in the table, PK is a NUMBER, not IDENTITY (this is obviously a defect and will be changed later on, but now I have to deal with that since I don't have rights to change DB structure, however I need to prepare CRUD demo). I don't want to use some C# value generator, but instead - DB remedy. So I tried to use the following (but it did not work - the expression is ignored):

b.HasKey(x => x.Id);b.Property(x => x.Id).HasColumnName("C_LICENCE").IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql("select round(dbms_random.value(100000, 999999)) from dual");

I suspect it's probably because int primary column is never null :) But anyway, I need to somehow force it to be generated via SQL always.