在 C# 中使用 SQLite.NET 获取最后一个插入 ID

问题描述 投票:0回答:11

我有一个简单的问题,但解决方案并不那么简单......我目前正在将一些数据插入数据库,如下所示:

kompenzacijeDataSet.KompenzacijeRow kompenzacija = kompenzacijeDataSet.Kompenzacije.NewKompenzacijeRow();
kompenzacija.Datum = DateTime.Now;
kompenzacija.PodjetjeID = stranka.id;
kompenzacija.Znesek = Decimal.Parse(tbZnesek.Text);

kompenzacijeDataSet.Kompenzacije.Rows.Add(kompenzacija);

kompenzacijeDataSetTableAdapters.KompenzacijeTableAdapter kompTA = new kompenzacijeDataSetTableAdapters.KompenzacijeTableAdapter();
kompTA.Update(this.kompenzacijeDataSet.Kompenzacije);

this.currentKompenzacijaID = LastInsertID(kompTA.Connection);

最后一行很重要。为什么我要提供连接?有一个名为 last_insert_rowid() 的 SQLite 函数,您可以调用它并获取最后一个插入 ID。问题是它绑定到一个连接,并且 .NET 似乎正在为每个数据集操作重新打开和关闭连接。我认为从表适配器获得连接会改变一切。但事实并非如此。

有人知道如何解决这个问题吗?也许从哪里获得持续的连接?或者也许更优雅的东西?

谢谢你。

编辑:

这也是事务的问题,如果我想使用事务,我需要相同的连接,所以这也是一个问题...

c# sql sqlite
11个回答
88
投票

将 C# (.net 4.0) 与 SQLite 结合使用,SQLiteConnection 类有一个属性

LastInsertRowId
,它等于最近插入(或更新)元素的主整数键。

如果表没有主整数键,则返回 rowID(在这种情况下,rowID 是自动创建的列)。

请参阅 https://www.sqlite.org/c3ref/last_insert_rowid.html 了解更多信息。

对于将多个命令包装在单个事务中,事务开始之后和提交之前输入的任何命令都是一个事务的一部分。

long rowID;
using (SQLiteConnection con = new SQLiteConnection([datasource])
{
    SQLiteTransaction transaction = null;
    transaction = con.BeginTransaction();

    ... [execute insert statement]

    rowID = con.LastInsertRowId;

    transaction.Commit()
}

55
投票
select last_insert_rowid();

您需要将其作为标量查询执行。

string sql = @"select last_insert_rowid()";
long lastId = (long)command.ExecuteScalar(sql); // Need to type-cast since `ExecuteScalar` returns an object.

9
投票

我正在使用 Microsoft.Data.Sqlite 包,但没有看到 LastInsertRowId 属性。但您不必创建第二次数据库访问来获取最后一个 id。相反,将两个 sql 语句组合成一个字符串。

string sql = @"
    insert into MyTable values (null, @name);  
    select last_insert_rowid();";

using (var cmd = conn.CreateCommand()) {
    cmd.CommandText = sql;
    cmd.Parameters.Add("@name", SqliteType.Text).Value = "John";
    int lastId = Convert.ToInt32(cmd.ExecuteScalar());
}

8
投票

last_insert_rowid() 是解决方案的一部分。它返回行号,而不是实际 ID。

cmd = CNN.CreateCommand();
cmd.CommandText = "SELECT last_insert_rowid()";
object i = cmd.ExecuteScalar();

cmd.CommandText = "SELECT " + ID_Name + " FROM " + TableName + " WHERE rowid=" + i.ToString();
i = cmd.ExecuteScalar();

3
投票

Microsoft 的参考文献和 SQLite 的参考文献似乎都有答案,这就是为什么有些人可以使用 LastInsertRowId 属性,而另一些人则不能。

我个人不使用 PK,因为它只是 rowid 列的别名。使用 rowid 的速度大约是您创建的 rowid 的两倍。如果我有一个用于 PK 的 TEXT 列,我仍然使用 rowid 并且只是使文本列唯一。 (仅适用于 SQLite 3。您需要自己的 v1 和 v2,因为真空会改变 rowid 数字)

也就是说,从最后插入的记录中获取信息的方法是下面的代码。由于该函数对自身进行了左连接,因此我将其限制为 1 只是为了速度,即使您不这样做,主 SELECT 语句中也只会有 1 条记录。

SELECT my_primary_key_column FROM my_table
WHERE rowid in (SELECT last_insert_rowid() LIMIT 1);

2
投票

SQLiteConnection 对象有一个属性,因此不需要额外的查询。 INSERT 之后,您只需使用用于 INSERT 命令的 SQLiteConnection 对象的 LastInsertRowId 属性。 LastInsertRowId属性的类型是Int64。 当然,正如您现在已经知道的那样,要使自动增量起作用,表上的主键必须设置为 AUTOINCRMENT 字段,这是另一个主题。


1
投票
    database = new SQLiteConnection(databasePath);

    public int GetLastInsertId()
    {
        return (int)SQLite3.LastInsertRowid(database.Handle);
    }

0
投票
# How about just running 2x SQL statements together using Execute Scalar?
# Person is a object that has an Id and Name property

var connString = LoadConnectionString(); // get connection string
using (var conn = new SQLiteConnection(connString)) // connect to sqlite
{

    // insert new record and get Id of inserted record
    var sql = @"INSERT INTO People (Name) VALUES (@Name);
                SELECT Id FROM People
                ORDER BY Id DESC";

    var lastId = conn.ExecuteScalar(sql, person);
}

0
投票

在 EF Core 5 中,您可以在对象本身中获取 ID,而无需使用任何“最后插入”。

例如:

var r = new SomeData() { Name = "New Row", ...};

dbContext.Add(r);

dbContext.SaveChanges();

Console.WriteLine(r.ID);

您将获得新的 ID,而无需考虑使用正确的连接或线程安全等。


0
投票

如果您使用的是 Microsoft.Data.Sqlite 包,则它的

LastInsertRowId
类中不包含
SqliteConnection
属性,但您仍然可以使用底层
last_insert_rowid
库调用
SQLitePCL
函数。这是一个扩展方法:

using Microsoft.Data.Sqlite;
using SQLitePCL;

public static long GetLastInsertRowId(this SqliteConnection connection)
{
    var handle = connection.Handle ?? throw new NullReferenceException("The connection is not open.");
    return raw.sqlite3_last_insert_rowid(handle);
}

0
投票

我相信在插入语句上使用 Returning 子句是最简单、最可靠的方法。您只需执行正常的插入操作并返回您的 Id 列即可。对于支持 RowId 的表,可以标准化如下:

insert into MyTable (Column1, Column2) Values (Val1, Val2) Returning RowId;

在 .Net 中,您只需运行它并使用

ExecuteScalar
返回值即可。

© www.soinside.com 2019 - 2024. All rights reserved.