NHibernate批量恢复备份似乎不可能

时间:2016-09-13 15:42:55

标签: c# hibernate nhibernate fluent-nhibernate

我正在尝试使用NHibernate执行数据恢复,但是我遇到了各种错误,从外键违规到主键违规以及介于两者之间的所有错误。

为了给出一些背景知识,我创建了一个&#34; Base&#34;我的应用程序中的每个类都继承的类(请不要对此进行评论,这是我需要/想要的)。 因此,要执行备份,我只需调用session.QueryOver<BaseClass>().List<BaseClass>()即可获取所有数据,将其序列化为javascript,压缩并保存。这就是我创建备份的方式。 现在恢复......

我轻松地反序列化备份,获得正确的类型和所有内容。

我已经尝试使用session.save(item, item.Id),使用与原始数据库中相同的ID重新放回项目,但NHibernate似乎并不喜欢这样,特别是当我在表(或类)之间有外键。

浏览互联网,似乎我的答案就在于无国籍会议。我试过这些,但我仍然会遇到各种各样的错误。

我试过的一件事是将所有插入包装在try-catch中,然后重试直到我不再出错。这种方式有效,但是当我拨打session.Commit时,我收到一条错误消息,其中包含大量违反PRIMARY KEY约束&#39; 消息。我已将所有插入包装到1个事务中(写这篇文章时我想尝试取出事务)....如果没有事务,它似乎已经保存了一些数据。我想我应该有一个交易,因为我希望能够保证所有数据都没有被恢复,以使恢复更加可靠。

使用try-catch似乎并不可靠,这也意味着我必须猜测在失败的项目上重试插入操作的次数。

我想补充的一个重要注意事项是,当我的代码运行时,我对类型为BaseClass的类或类型一无所知,并带有Id字段。因此,给出错误的一个类是菜单类。它有一个属性List<Menu> - childMenus和另一个类型为Menu的属性 - parentMenu。这两个属性使用流畅的nhibernate映射为HasManyReferences,这就是我认为这些应该被映射的方式。这是一种给我带来问题的类,因为NHibernate创建了外键。这在我看来是好的,除了现在我不能轻易地进行恢复。

如果我没有得到合适的答案或很快得出结论,我的解决方案是尝试订购要恢复的项目,以便任何&#34;看起来&#34;就像它可能有一个带有外键的父对象(类型为BaseClass的属性)一样,我会将这些项排序到列表中并最后插入它们,并希望避免外键约束违规。

但我希望还有其他选择。

此外,当我进行恢复时,Id生成器设置为已分配,因此我不认为我的问题与未知或无效的ID有关。在原始数据中,我的身份证是GUID&#39; s。 (我可能会在以后将此更改为hilo整数,但一次只能出现一个问题。)

非常感谢任何帮助。

提前致谢...

1 个答案:

答案 0 :(得分:0)

除非我找到更好的替代方案,否则我的解决方案将涉及使用类似于以下内容的代码强制数据进入数据库:

            var existingCount = 0l;
            var lastCount = -1l;
            while (existingCount < items.Count)
            {
                using (var session = factory.OpenSession())
                {
                    existingCount = session.CreateCriteria<BaseClass>()
                                           .SetProjection(Projections.RowCountInt64())
                                           .List<long>()
                                           .Sum();
                    session.Flush();
                }

                if (existingCount == items.Count)
                {
                    break; // success
                }

                if (lastCount == existingCount)
                {
                    throw new Exception("Error restoring backup, no change after retrying inserting new items.");
                }
                lastCount = existingCount;

                try
                {
                    using (var session = factory.OpenSession())
                    {
                        var existingItems = session.QueryOver<BaseClass>().List<BaseClass>().ToList();
                        SaveItemsToDb(existingItems, items, session); // checks if item already exists, if not, tries to save it. Also has some try-catch processing

                        session.Flush();
                    }
                }
                catch (Exception exception)
                {
                    //Do nothing, just try again.
                }
            }