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.