如何避免重复输入并使用NHibernate获取相应原始条目的ID

时间:2014-03-02 08:42:25

标签: c# nhibernate

我是NHibernate的初学者。我正在使用NHibernate 3.3和C Sharp。我将数据从文件插入到mysql数据库。我的文件有重复的条目。我有一个PERSON表,其主键为id,并自动递增为:

    id | firstname | lastname | fullname | dob | city

现在我想避免重复保存到数据库,并希望从数据库中获取原始条目的id。

例如: 文件中有4条记录:

firstname|lastname|fullname|dob|city
-------------------------------------------
a|b|ab|1|c
c|d|cd|2|e
a|b|ab|1|c
f|g|fg|4|h

现在假设我已经使用NHibernate 3.3保存了前两个记录。人员表格如下:

id|firstname|lastname|fullname|dob|city
------------------------------------------
1|a|b|ab|1|c
2|c|d|cd|2|e

在我当前的实现中,与文件的第1行相同的第3行正在保存在表中。我不想这样做。我想避免在表格中重复输入。我也不想每次都执行查询来检查以前是否存在于数据库中的记录。此外,如果这样的重复条目已经在表中,我想填充其ID。对于这种情况,它应该是1.

如果有人可能建议我解决这个问题,那真的会很棒。

1 个答案:

答案 0 :(得分:2)

您应该在字段上创建唯一索引:

CREATE UNIQUE INDEX "PERSON_idx" ON "PERSON"
  USING btree (firstname, lastname, fullname, dob, city);

然后,每当您尝试插入一行,这些字段等于某个已存在的行时,数据库服务器将引发异常。

要获取冲突行的ID,在某些情况下,解析从数据库返回的错误文本是可行的,但我建议只在发生这种情况时从数据库中检索记录。

现在可能有两条通用路径来解决获取冲突行的问题。特别是,使用NHibernate的session.Save不一定会因违反唯一约束而抛出异常,因为在提交事务之前可能不会发出INSERTs。在这种情况下,很难猜出哪些行导致了错误(没有查看数据库日志)。

使用INSERTs代替IStatelessSession可以解决延迟ISession的此问题,这将使INSERTs立即发布(AFAIK)。然后就可以有这样的东西:

using (var tx = statelessSession.BeginTransaction())
{
    foreach (var person in persons)
    {
        try
        {
            statelessSession.Insert(person);
        }
        catch (GenericADONetException e)
        {
            // Further check that it's really caused by violating the unique constraing (database-specific) and handling the situation
        }
    }
    tx.Commit();
}

如果您需要使用ISession或由于其他原因不喜欢此解决方案,您可以在插入行之前通过发出单个SELECT来获取所有重复项:

var conflictingRows = session.Query<Person>().Where(p =>
      (p.FirstName == persons[0].FirstName && p.LastName == persons[0].LastName && ...)
   || (p.FirstName == persons[1].FirstName && p.LastName == persons[1].LastName && ...)
   ...
   || (p.FirstName == persons[persons.Count - 1].FirstName && p.LastName == persons[persons.Count - 1].LastName && ...));

然后,可以在内存中轻松获取与要插入的记录对应的ID。你必须动态地构建这个表达式,但那是not a big deal either


PS:由于您要求所有字段的组合都是唯一的,因此您可以完全删除id列,并将所有字段用作复合主键。