Devart.Data.Oracle.EFCore - Как использовать последовательность, чтобы установить значение столбца PK? - PullRequest
0 голосов
/ 17 октября 2018

Я использую Entity Framework Core 2.1.4 с базой данных Oracle 11 и провайдером Devart.Data.Oracle.EFCore.Первый подход к базе данных.

Я хочу получить значение последовательности для столбца идентификатора (первичный ключ) при вставке, не устанавливая его явно каждый раз.Итак, основываясь на аналогичной информации с SQL Server, я сделал это следующим образом:

Entity

public class Foo
{
    public int Id { get; set; }
    public double Value { get; set; }
}

Mapping (метод OnModelCreating)

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");
});

Добавление значения:

using (var dbContext = new FooDbContext())
{
    var foo = new Foo()
    {
        Value = 5
    };
    dbContext.Foos.Add(foo);
    dbContext.SaveChanges();
}

В SaveChanges:

OracleException: ORA-01400: cannot insert NULL into ("SCHEMA"."FOOS"."ID")

Я также зарегистрировал запрос EF.Как видите, в вставке нет столбца идентификатора:

INSERT INTO SCHEMA.FOOS (VALUE)
  VALUES (:p0)

Я пытался использовать просто SEQ_FOO.NEXTVAL вместо методов полного выбора или EF по умолчанию (например, HasDefaultValueSql), но ничего не получалось.Даже если я наберу:

ForOracleHasDefaultValueSql("asdasd");

Нет ошибок с этим - только то же исключение, что и выше.Кажется, EF никогда не называет этот SQL.

Я что-то упускаю?А может это внутренняя проблема Деварта?

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

Хорошо, у меня есть решение.Кажется, нам нужно использовать ValueGenerator.Моя реализация ниже.

Отображение

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

SequenceValueGenerator (обратите внимание, что ValueGenerator имеет тип EF Core)

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);
            }
        }
    }
}

Кажется, работает так, как мне нужно.

0 голосов
/ 17 октября 2018

Отображение:

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");
    });
}

Код:

    // 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();
    }

Проверка SQL, сгенерированного в dbMonitor.Это то, что вам нужно?

...