我有一个web api post方法,它在Oracle数据库的表中插入一个新行。表的主键是一个序列值,我遇到了问题。如何在实体框架中执行my_primary_key_seq.nextval
?目前,这段代码可以工作,但当通过旧的.net网络表单插入新行时,它将违反PK唯一约束,该表单使用序列下一个值作为下一个主键。
decimal nextPK = context.FORMPPs.OrderByDescending(p => p.PPID).FirstOrDefault().PPID + 1;
item.PPID = nextPK;
context.FORMPPs.Add(item);
int result = context.SaveChanges();
我遇到了同样的问题,并在该网站和Oracle的帮助下解决了它。我假设您使用的是数据库优先,因为您提到另一个遗留应用程序使用相同的数据库。
我不得不做一些事情。就像Daniel Gabriel提到的,如果你允许Oracle管理身份,你就不需要调用序列来找出号码,数据库会帮你处理它。但是要实现这一点有点棘手,因为您可能需要对数据库进行一系列更改。
-
在标识列上创建序列(您已经这样做了)。
-
创建一个触发器以在插入时自动调用序列。http://www.oracle-base.com/articles/misc/autonumber-and-identity.php
-
更改实体框架模型。我首先使用EF数据库,发现这篇文章解释了我需要更改模型以将表的标识列的属性设置为
StoreGeneratedPattern="Identity"
VS实体框架中的Oracle实体不更新代码中的主键
- 但我不喜欢每次从数据库中刷新EF模型时都必须重新添加此更改。双击.edmx文件,然后在数据库关系图中找到表,高亮显示关系图中的标识列,然后在属性窗口中,将StoreGeneratedPattern值更改为identity。这应该会使它持续存在,即使你更新你的EF模型
我解决这个问题的方法是使用原始SQL查询从序列中选择一个新值。
即
decimal nextPK = context.Database.SqlQuery<decimal>("SELECT my_primary_key_seq.nextval FROM dual").First();
然后在将该值添加到上下文之前,将其分配给新对象。
我的两分钱贡献:
string querySeq = "SELECT SCH.YOUR_SEQUENCE.NEXTVAL FROM DUAL";
var conn = (OracleConnection)dbContext.Database.GetDbConnection();
conn.Open();
var command = new OracleCommand(querySeq, conn);
decimal sequence = (decimal) command.ExecuteScalar();
您可以从上下文中获取数据库连接,并将其与OracleCommand类一起使用,以便直接使用ODP.net库执行SQL查询。
我用它作为参考:
https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Querying/RawSQL
Data/OracleSequenceContext.cs
using Microsoft.EntityFrameworkCore;
namespace EFQuerying.RawSQL;
public class OracleSequenceContext : DbContext
{
public DbSet<OracleSequence> dbsetOracleSequences { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<OracleSequence>(
eb =>
{
eb.HasNoKey();
});
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// don't put this in code.
optionsBuilder.UseOracle("Data Source=XXXXXXX;User ID=TTTTT;Password=PPPPP;");
}
}
OracleSequence.cs
using System.Collections.Generic;
namespace EFQuerying.RawSQL;
public class OracleSequence
{
public int SequenceValue { get; set; }
}
用法:
using (var seqContext = new OracleSequenceContext())
{
var seqList = seqContext.dbsetOracleSequences
.FromSqlRaw("SELECT SEQ_PUBLICATION.NEXTVAL as SequenceValue FROM DUAL")
.ToList();
Publication.PublicationId = seqList[0].SequenceValue;
}