【问题标题】:Dapper + MSAccess: How to get identifier of inserted rowDapper + MSAccess:如何获取插入行的标识符
【发布时间】:2016-09-20 09:16:51
【问题描述】:

我正在使用带有 C# 的 Dapper,后端是 MS Access。我的 DAL 方法在数据库中插入记录。我想返回插入行的唯一标识符(或使用唯一标识符更新的 POCO)。 我期待我的功能如下(我知道这不起作用;只是为了解释我想要的):-

public MyPoco Insert(MyPoco myPoco)
{
    sql = @"INSERT INTO MyTable (Field1, Field2) VALUES (@Field1, @Field2)";
    var param = GetMappedParams(myPoco);//ID property here is null.
    var result = _connection.Query<MyPoco>(sql, param, null, false, null, CommandType.Text);.Single();
    return result;//This result now contains ID that is created by database.
}

我来自 NHibernate 世界,POCO 会自动使用 NH 进行更新。如果不;我们可以调用 Refresh 方法并更新 ID。 我不知道如何使用 Dapper 实现这一目标。

我阅读了关于 SO 的 this 问题,该问题与 SQL Server 无关。

另一个this 的问题没有被接受的答案。

我阅读了this 问题,其中接受的答案解释了使用@@Identity 的陷阱。

【问题讨论】:

  • 我想这是你的答案stackoverflow.com/questions/2230719/…
  • @progpow:您建议SELECT @@Identity。我不确定这是否可靠。我的应用程序是多用户应用程序,其中多个用户将同时在同一个表中插入记录。据我了解,不建议这样做。如果我错了,请纠正我。
  • 你可以测试,我写了一个答案,但找不到。使用隔离实例(设置 db=currentdb),在 sql 之前暂停并手动插入记录。我想你会发现它是真的。
  • 对不起;那是我的错误。 @@Identity 总是返回零,因为我从未明确打开(和关闭)连接。在这种情况下,Dapper 在内部打开(和关闭)连接。在为执行@@Identity 查询打开新连接时,它返回零。
  • @tomRedox - 它专门指event-driven Data Macros,这是一种特殊的宏,其行为类似于trigger。其他插入,例如从 VBA 代码或绑定表单执行的插入,不太可能导致使用 SELECT @@IDENTITY 出现问题。

标签: c# ms-access dapper


【解决方案1】:

这对我有用:

static MyPoco Insert(MyPoco myPoco)
{
    string sql = "INSERT INTO MyTable (Field1, Field2) VALUES (@Field1, @Field2)";
    _connection.Execute(sql, new {myPoco.Field1, myPoco.Field2});
    myPoco.ID = _connection.Query<int>("SELECT @@IDENTITY").Single();
    return myPoco;  // This result now contains ID that is created by database.
}

请注意,这将适用于 Access 数据库的 OleDbConnection,但它不会适用于 OdbcConnection

编辑回复:评论

为了确保连接在 INSERT 和 SELECT 调用之间保持打开状态,我们可以这样做:

static void Insert(MyPoco myPoco)
{
    string sql = "INSERT INTO MyTable (Field1, Field2) VALUES (@Field1, @Field2)";
    bool connAlreadyOpen = (_connection.State == System.Data.ConnectionState.Open);
    if (!connAlreadyOpen)
    {
        _connection.Open();
    }
    _connection.Execute(sql, new {myPoco.Field1, myPoco.Field2});
    myPoco.ID = _connection.Query<int>("SELECT @@IDENTITY").Single();
    if (!connAlreadyOpen)
    {
        _connection.Close();
    }
    return;  // (myPoco now contains ID that is created by database.)
}

【讨论】:

  • 只要_connection 明确打开之前 INSERT INTO 并关闭之后 SELECT @@IDENTITY 调用,它就可以工作。我没有正确处理连接。此外,必须了解使用@@Identity 的陷阱;我在我的问题中提供了链接。
【解决方案2】:

只是一些额外的想法:如果 @@Identity pitfalls 是一个问题,那么另一种选择是提前在代码中创建一个新的 GUID,然后将该 GUID 与其余数据一起插入,而不是让 Access 创建创建新记录时的标识值。

我很欣赏这仅在您的特定情况允许表的 GUID 主键时才有效,但它确实保证您知道您刚刚插入的记录的键的真实值。

或者,如果您不需要 GUID 键,您可以创建一个包含单行的表,其中包含应用程序中任何手动管理的键的当前种子值。然后,您可以在每次要插入新记录时手动增加特定种子的值。与 GUID 方法一样,您将手动将 ID 与记录一起插入,这次 ID 将是您刚刚检索到的新增加的种子。

同样,这应该保证您每次插入都有一个唯一的键,尽管现在您正在为每个插入执行一次读取和两次写入。

【讨论】:

  • Guid 是不错的选择,但由于其大小和性能不足,许多人会放弃。其主要目标是让数据复制投诉。可能这就是为什么微软将其命名为Autonumber - Replication ID。我猜很少有开发人员在 MS Access 中使用这种数据类型。
  • 您建议的其他替代方案(在代码中生成 id)看起来更好。你说的缺点是额外的数据库调用。使用不使用 DB 的算法可以轻松避免这些问题。
猜你喜欢
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
  • 2012-11-14
相关资源
最近更新 更多