2009-09-25 103 views
0

我在NHibernate中遇到了一些独特约束的麻烦。NHibernate的独特约束条件

我有一个用户实体映射到一个唯一的用户名属性约束。我想要做的是能够在新用户添加之前以及在现有用户更新用户名之前检查特定用户名是否存在。

第一种情况(添加一个新用户)工作得很好。但是,当我尝试在更新现有用户之前检查用户名是否存在时,我得到了违反约束的情况。以下是我的Save方法的代码。

public void Save<T>(T entity) where T : User 
    { 
     using (var session = GetSession()) 
     using (var transaction = session.BeginTransaction()) 
     { 
      try 
      { 
       CheckIfUsernameExists(entity); 

       session.SaveOrUpdate(entity); 
       session.Flush(); 
       transaction.Commit(); 
      } 
      catch (HibernateException) 
      { 
       transaction.Rollback(); 
       throw; 
      } 
     } 
    } 

的约束被违反在CheckIfUsernameExists()方法,它看起来像这样:

public void CheckIfUsernameExists<T>(T entity) where T : User 
    { 
     var user = GetUserByUsername(entity); 
     if (user != null) 
      throw new UsernameExistsException(); 
    } 

    private T GetUserByUsername<T>(T entity) where T : User 
    { 
     var username = entity.Username; 
     var idToExclude = entity.Id; 

     var session = GetSession(); 

     var user = session.CreateCriteria<T>() 
      .Add(Restrictions.Eq("Username", username)) 
      .Add(Restrictions.Not(Restrictions.IdEq(idToExclude))) 
      .UniqueResult() as T; 

     return user; 
    } 

它是导致它崩溃从而导致NHibernateException的session.CreateCriteria()行(SQLiteException ),消息“由于违反约束而中止。列用户名不唯一”。

它与NHibernate的现金有关吗?传递给save方法的实体在session.CreateCriteria()被调用时已用所需的用户名更新。也许我做这一切都错了(我是一个NHibernate的初学者),所以请随时陈述明显并提出替代方案。

任何帮助非常感谢!

回答

0

嗯,我不确定问题的核心,但对于尝试查看用户是否已经存在的策略,为什么需要“.UniqueResult()”?

难道你不能只是假设得到一个与用户名相匹配的用户列表,并且没有与你当前用户相同的用户名(显然)。伪代码,好像我做这样的事情

public bool ExistsUsername(string username, int idToExclude) 
{ 
    IList<User> usersFound = someNHibernateCriteria excluding entries that have id = idToExclude 

    return (usersFound.Count > 0) 
} 
+0

回答你的问题是,我不知道。我已将代码更改为您的建议,但结果相同。感谢您的输入! – 2009-09-25 10:30:46

+1

好的...我想你在你的数据库中的“用户名”col放置了一个唯一的约束?此外,我读到,你有“传递给保存方法的实体已更新所需的用户名在会议..”我不会这样做。我会在之前调用ExistsUsername,这样你也可以避免使用“idToAvoid”。 – Juri 2009-09-25 10:37:49

+0

是的,数据库中有一个用户名限制。关于在更新实体之前调用ExistsUsername;这可能是一种可能性,但我需要进一步调查。谢谢。 – 2009-09-25 10:59:27

0

两个想法: - 你为什么不只是SaveOrUpdate,看看你是否成功。这在你的情况下是不可能的? - 我见过你提到SQLite。这是你真正的生产系统,还是你用来测试的东西?如果是这样,你是否检查过SQLite是否会造成问题,而查询是否可以针对全功能的DBMS? - SQLite经常遇到这样的问题,因为它不支持所有类型的约束......

+0

托马斯,我希望能够调用SaveOrUpdate,但由于我无法检查抛出什么类型的异常,我没有办法通知用户出了什么问题。这就是为什么我想抛出自己的异常(UsernameExistsException)。或者有没有办法让我不知道的更具体的NHibernate异常? 关于SQLite;是的,我们在本地开发mashines上使用SQLite,并进行集成测试。我们目前没有建立生产环境。我会牢记它,但SQLite似乎不可能处理这种简单的情况。 – 2009-09-25 10:54:58

+0

您是否通过NH映射通过hbm2ddl生成SQLite实例?那么这就是问题所在:SQLite不支持'ALTER TABLE'语句,AFAIK它们被默默地忽略。 如果您计划在生产中定位另一个DBMS,那么您就不能使用SQLite进行集成测试 - 这不是完全替代。这可能是快速和容易的,但它可能会给出错误的结果。 你应该花半个小时对一个完整的DBMS测试这段代码 - 我确信测试会通过... – 2009-09-26 04:39:53

+0

@Thomas Weller:恐怕情况并非如此。我们删除表中的表并使用模式导出来添加新表。关于SQLite进行集成测试,您的声明与我从很多人听到的完全相反。为什么不能用它进行集成测试?感谢您的输入! – 2009-10-08 20:46:11

0

你确定在CreateCriteria引发异常吗?因为,我没有看到如何从select语句获取SQLlite约束异常。我做同样的事情......

public bool NameAlreadyExists(string name, int? exclude_id) 
{ 
    ICriteria crit = session.CreateCriteria<User>() 
     .SetProjection(Projections.Constant(1)) 
     .Add(Restrictions.Eq(Projections.Property("name"), name)); 

    if (exclude_id.HasValue) 
     crit.Add(Restrictions.Not(Restrictions.IdEq(exclude_id.Value))); 

    return crit.List().Count > 0; 
} 

我会看看生成的SQL的顺序,看看是什么原因造成的。如果该实体在该会话中加载,则可能在查询之前更新该实体。