oracle - Devart.Data.Oracle.EFCore - 如何使用序列来设置 PK 列值?

标签 oracle frameworks entity core devart

我将 Entity Framework Core 2.1.4 与 Oracle 11 数据库和 Devart.Data.Oracle.EFCore 提供程序一起使用。
数据库优先方法。

我想在插入时从 ID 列(主键)的序列值中获取,而无需每次都明确设置。
因此,基于与 SQL Server 的类似信息,我按以下方式进行了操作:

实体

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

映射(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 查询。如您所见,插入中没有 ID 列:
INSERT INTO SCHEMA.FOOS (VALUE)
  VALUES (:p0)

我试图简单地使用 SEQ_FOO.NEXTVAL 而不是全选或默认 EF 方法(如 HasDefaultValueSql),但没有任何效果。即使我输入:
ForOracleHasDefaultValueSql("asdasd");

这没有错误 - 只有与上面相同的异常(exception)。似乎 EF 从不调用该 SQL。

我错过了什么重要的东西吗?或者它可能是内部 Devart 问题?

最佳答案

好的,我有解决方案。看来我们需要使用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);
            }
        }
    }
}

它似乎按我的需要工作。

关于oracle - Devart.Data.Oracle.EFCore - 如何使用序列来设置 PK 列值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52853862/

相关文章:

Oracle 日期格式 "2009-02-13T11:46:40+00:00"

c# - 禁用或重置 .Net Framework Init 错误

c# - C# 中撤消重做实现的最佳实践

linq - 使用具有外键的 EntityCollection 初始化 List<T>

ios - 使用 CoreData 以编程方式创建实体/表,并在适用于 iOS 的 Swift 3 中将值插入该实体

sql - Oracle - 将列数据映射到一个值

java - 使用相同的 JDBC 驱动程序性能连接到多个数据库

java - oracle Thin驱动程序使用哪个jar文件?

macos - 找不到符号 _OBJC_IVAR_$_NSView._layer(在 AppKit 中)仅在 10.7 上,在 10.8 和 10.9 上工作正常

symfony - PreUpdate 级联实体持久化 symfony 2.3