2014-09-23 102 views
1

情况

我有一个通过NHibernate(3.3.3-SP1)映射的数据库表。该应用程序在.NET4.0上运行,映射通过FluentNHibernate(1.4.0)完成。NHibernate SaveOrUpdate没有主键

CREATE TABLE Movies 
(id INT PRIMARY KEY, 
yearPublished DATETIME NOT NULL, 
name NVARCHAR(500) NOT NULL, 
description NTEXT NOT NULL) 

的数据将是这样的:

 
id | yearPublished | name     | description 
---+---------------+------------------------+-------------------------------------------- 
1 | 1968   | 2001: A Space Oddyssey | An epic drama of adventure and exploration 

的问题

我创建此表的新的实体,并希望避免增加一个以上的实体相同的实世界的事情。我知道有Session.SaveOrUpdate,也有一种方法可以使它与复合和自然ID一起工作,但那不是我想要的,因为我的实体实际上有一个主键,而且我确实只需要组合键就可以确保没有重复项在数据库中。

var movie = new Movies 
{ 
    yearPublished = 1968, 
    name = "2001: A Space Oddyssey", 
    description = "An awesome journey to Jupiter" 
}; 

// Behavior right now: 

// Adds a new movie besides the fact that 
// the movie is already in the database 
// but now has two entries 
session.SaveOrUpdate(movie); 

Assert.IsTrue(movie.id == 2 && movie.description == "An awesome journey to Jupiter"); 

// What I really want is to be able to define what 
// makes an object unique other than the primary key; 
// in this scenario it should look for a combination 
// of "yearPublished" and "name" 
session.MyAwesomeSaveOrUpdate(movie); 

Assert.IsTrue(movie.id == 1 && movie.description == "An epic drama of adventure and exploration"); 

这是功能性的地方NHibernate的(例如,通过自定义映射),或者我有获取从DB候选人,并用手做呢?

谢谢!

回答

0

我加入数据库中的自然键字段的唯一约束,并使用异常转换到SQL Server异常转换成一个我的应用程序可以处理解决这个问题。

public class SqlServerExceptionConverter : ISQLExceptionConverter 
{ 
    public Exception Convert(AdoExceptionContextInfo adoExceptionContextInfo) 
    { 
     var sqlException = adoExceptionContextInfo.SqlException as SqlException; 
     if (sqlException != null) 
     { 
      // 2601 is unique key, 2627 is unique index; same thing: 
      // http://blog.sqlauthority.com/2007/04/26/sql-server-difference-between-unique-index-vs-unique-constraint/ 
      if (sqlException.Number == 2601 || sqlException.Number == 2627) 
      { 
       // my custom exception 
       return new UniqueKeyException(sqlException.Message, sqlException); 
      } 
     } 
     return adoExceptionContextInfo.SqlException; 
    } 
} 

另一种方法我能想到的是查询插入之前匹配的记录数据库,但是这不是万无一失,因为一个记录可以选择与您的插入之间插入。

+0

我真的不使用控制流异常的粉丝,但至少它似乎工作。尽管如此,我一直在使用DIY方法 – mfeineis 2017-04-21 22:44:59

+1

如果您想处理数据库异常,则没有其他选择。您可以通过预先检查数据或包含where子句来避免它们,但是捕获异常并将其转换为应用程序可以处理的是唯一的万无一失的方法。 – 2017-04-22 17:27:28