代码之家  ›  专栏  ›  技术社区  ›  HakonB

NHibernate中多对多关系使用哪种算法

  •  2
  • HakonB  · 技术社区  · 17 年前

    public void Import() {
        ...
        foreach (var fileName in fileNames) {
            var photo = new Photo { FileName = fileName };
            AddDefaultTags(_session, photo, fileName);
            _session.Save(photo);
        }
        ...
    }
    
    private void AddDefaultTags(…) {
        ...
        var tag =_session.CreateCriteria(typeof(Tag))
                        .Add(Restriction.Eq(“Name”, year.ToString()))
                        .UniqueResult<Tag>();
    
        if (tag != null) {
            photo.AddTag(tag);
        } else {
            var tag = new Tag { Name = year.ToString()) };
            _session.Save(tag);
            photo.AddTag(tag);
        }
    }
    

    我的问题是当标签不存在时,例如新年的第一张照片。AddDefaultTags方法检查数据库中是否存在标记,然后创建标记并将其添加到NHibernate中。这在添加单张照片时效果很好,但在新的一年和同一工作单元中导入多张照片时会失败,因为它仍然不存在于数据库中,并且会再次添加。当完成工作单元时,它失败了,因为它试图在Tags表中添加两个同名条目。..

    3 回复  |  直到 15 年前
        1
  •  2
  •   Community Mohan Dere    9 年前

    你需要奔跑 _session.Flush() 如果你的条件不应该返回过时的数据。 或者,通过设置 _session.FlushMode 到汽车。

    使用刷新模式。自动,会话将在执行标准之前自动刷新。

    编辑:而且很重要!在阅读您展示的代码时,看起来您并没有为您的工作单元使用事务。我建议您将工作单元包装在事务中——这是FlushMode所必需的。如果您使用NH2.0+,则自动工作!

    请点击此处进一步阅读: NHibernate ISession Flush: Where and when to use it, and why?

        2
  •  0
  •   Maggie    17 年前

    如果您希望在每次检查新标记时将其放入数据库中,则需要在保存后提交事务以将其放入其中。

    另一种方法是在处理照片之前将标签读入收藏。 然后,就像你说的,你会搜索本地并根据需要添加新标签。完成文件夹后,您可以提交会话。

    你应该发布你的映射,因为我可能没有正确解释你的问题。

        3
  •  0
  •   Stefan Steinegger    17 年前

    这就是典型的“锁定不存在的东西”问题。我已经面对过好几次了,仍然没有一个简单的解决方案。

    以下是我目前所知的选项:

    • 乐观主义:对名称有一个独特的约束,让其中一个会话进行提交。然后你再试一次。你必须确保当另一个错误发生时,你不会陷入无限循环。
    • 悲观:当你添加一个新的Tag时,你会使用TSQL锁定整个Tag表。
    • .NET锁定:您可以使用同步线程。NET锁。只有当并行事务处于同一流程中时,这才有效。
    • 使用自己的会话创建标签(见下文)

    例子:

    public static Tag CreateTag(string name)
    {
      try
      {
        using (ISession session = factors.CreateSession())
        {
          session.BeginTransaction();
          Tag existingTag = session.CreateCriteria(typeof(Tag)) /* .... */
          if (existingtag != null) return existingTag;
          {
            session.Save(new Tag(name));
          }
          session.Transaction.Commit();
        }
      }
      // catch the unique constraint exception you get
      catch (WhatEverException ex)
      {
        // try again
        return CreateTag(name);
      }
    }
    

    这看起来很简单,但有一些问题。你总是会得到一个标签,它要么是现有的,要么是创建的(并立即提交)。但是,您获得的标签来自另一个会话,因此它被分离用于您的主会话。您需要使用级联(您可能不想)或更新将其附加到会话中。

    创建标签不再与主事务耦合,这是目标,但也意味着回滚事务会将所有创建的标签留在数据库中。换句话说:创建标签不再是交易的一部分。

    推荐文章