NHibernate唯一约束

NHibernate唯一约束,nhibernate,fluent-nhibernate,Nhibernate,Fluent Nhibernate,我在NHibernate中遇到了一些独特的约束问题 我有一个用户实体,它映射为Username属性的唯一约束。我想做的是能够在添加新用户之前以及在现有用户更新其用户名之前检查特定用户名是否存在 第一个场景(添加新用户)运行良好。但是,当我在更新现有用户之前尝试检查用户名是否存在时,我会遇到一个约束冲突。下面是我的Save方法的代码 public void Save<T>(T entity) where T : User { using (var session

我在NHibernate中遇到了一些独特的约束问题

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

第一个场景(添加新用户)运行良好。但是,当我在更新现有用户之前尝试检查用户名是否存在时,我会遇到一个约束冲突。下面是我的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;
            }
        }
    }
公共作废保存(T实体),其中T:用户
{
使用(var session=GetSession())
使用(var transaction=session.BeginTransaction())
{
尝试
{
CheckIfUsernameExists(实体);
会话。保存或更新(实体);
session.Flush();
Commit();
}
捕获(休眠异常)
{
transaction.Rollback();
投掷;
}
}
}
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;
    }
public void CheckIfUsernameExists(T实体),其中T:User
{
var user=GetUserByUsername(实体);
如果(用户!=null)
抛出新用户名existsexception();
}
私有T GetUserByUsername(T实体),其中T:User
{
var username=entity.username;
var idToExclude=entity.Id;
var session=GetSession();
var user=session.CreateCriteria()
.Add(Restrictions.Eq(“用户名”,Username))
.Add(Restrictions.Not(Restrictions.IdEq(idToExclude)))
.UniqueResult()作为T;
返回用户;
}
正是session.CreateCriteria()行导致其崩溃,导致出现NHibernateeException(SQLiteException),消息为“由于约束冲突而中止。列用户名不唯一”

是否与NHibernate现金有关?在调用session.CreateCriteria()时,传递给save方法的实体已使用所需的用户名更新

也许我做错了(我是一个NHibernate初学者),所以请随意陈述明显的问题并提出替代方案


非常感谢您的帮助

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

难道你不能假设得到一个用户列表,这些用户与该用户名匹配,并且与当前用户的id不同(显然)。伪代码就像我要做的那样

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

   return (usersFound.Count > 0)
}
public bool ExistsUsername(字符串用户名,int-idToExclude)
{
IList usersFound=someNHibernateCriteria,不包括id=idToExclude的条目
返回(usersFound.Count>0)
}
两个想法: -为什么不保存或更新,看看是否成功。在您的场景中,这不可能吗?
-我见过你提到SQLite。这是您真正的生产系统,还是您用于测试的东西。如果是这样的话,您是否检查过是否是SQLite造成了问题,并且查询是针对功能齐全的DBMS工作的SQLite经常会出现这种问题,因为它不支持所有类型的约束…

您确定会在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;
}
public bool NameAlreadyExists(字符串名,int?排除id)
{
ICriteria crit=session.CreateCriteria()
.设定投影(投影.常数(1))
.添加(限制条件、等式(投影、属性(“名称”)、名称));
if(排除_id.HasValue)
添加限制(Restrictions.Not(Restrictions.IdEq(exclude_id.Value));
返回crit.List().Count>0;
}
我将查看生成的sql的顺序,看看是什么导致了它。如果该实体是在该会话中加载的,那么它可能会在查询之前得到更新

transaction.Rollback()不会从会话缓存中删除实体,请改用session.execute()

见:
-

你的问题的答案是,我不知道。我已将代码更改为您建议的代码,但结果是相同的。谢谢你的意见!好的……我猜您对数据库中的“username”列设置了唯一的约束?此外,我还了解到“传递给save方法的实体在会话时已使用所需的用户名进行了更新…”我不会这样做。我之前会调用ExistsUsername,这样您也可以避免使用“idToAvid”。是的,在db中有一个用户名约束。关于在更新实体之前调用ExistsUsername;这可能是一种可能性,但我需要进一步调查。谢谢。这只是一个优化逻辑的意见。当您实际上不知道用户名是否有效时,将用户名分配给实体听起来是错误的。这在逻辑上是不正确的。相反,我会检查这一点,比如在您的UI控制器上使用call ExistsUsername(用户名),如果是,则显示适当的消息,否则调用SaveUser(…)。@Juri:您建议的策略就是我们要的。我们现在在存储库的顶部有一个服务,用于处理唯一用户名检查。谢谢Thomas,我希望能够调用SaveOrUpdate,但由于我无法检查引发的异常类型,因此我无法通知用户出了什么问题。这就是为什么我想抛出自己的异常(UsernameExistsException)。或者有没有一种方法可以获得我不知道的更具体的NHibernate异常?关于SQLite;是的,我们在本地dev mashines和集成测试中使用SQLite。我们目前没有设置生产环境。我会记住这一点,但SQLite似乎不太可能不能处理这个简单的场景