对使用Nhibernate和Castle创建的重复记录进行故障诊断

时间:2012-04-23 20:43:10

标签: c# nhibernate inversion-of-control castle-windsor

我们正在使用.Net与Nhibernate和Castle for IOC(适用于所有服务和存储库)。最近的部署开始发生奇怪的事情,我无法跟踪问题。

我们在创建ObjA后从服务调用的存储库中有以下代码块:

    public void Save(IList<ObjA> listA, IList<ObjB> listB, ObjC c, Objd d) {
        using (var session = GetSession()) {
            using (var tx = session.BeginTransaction()) {
                try {
                    session.Save(c);
                    foreach (var a in listA) {
                        session.Update(a);
                    }
                    foreach (var b in listB) {
                        // unrelated field updates here
                        session.Save(b);
                    }
                    session.Update(d);
                    if (!tx.WasCommitted) {
                        tx.Commit();
                    }
                } catch (Exception) {
                    if (tx != null) {
                        tx.Rollback();
                    }
                    throw;
                }
            }
        }
    }

此代码称为listA中的1 ObjA,listB中的1 ObjB,以及ObjC和ObjD。

我们发现它是随机的(大约一半时间被调用)我们得到重复的ObjB和ObjC记录(这里唯一的对象是创建而不是更新)。由于ObjC有一个日期时间字段,我可以跟踪创建记录的时间,并且有时会在~12-18小时内创建5-100个重复记录。这是在数据库中创建ObjB和ObjC记录的唯一代码。

我之前从未见过这样的东西,似乎某些东西卡在内存中并且一直在间歇地调用这个函数(或Nhibernate调用)。我在其中一个似乎遇到此问题的服务器上重新启动了IIS,问题停止了,但第二天又在另一台服务器上启动了。

有没有人对可能导致这种情况的原因有任何想法? Castle或Nhibernate的配置中是否存在可能导致这些调用卡住并重复超过12-18小时(超过100次?)的内容?

感谢任何帮助:)

Service(){

    _saveLater = null;

    CalledByWS(){
        CreateObjA();
        CreateOtherObjs();  

    }   

    CreateObjA(){
        //Do a lot of stuff here

        var a = new ObjA{ };
        listToBeSaved.Add(a, SaveOrUpdate.Save);

        //Update other objects & add to the list

        if(xyz){
            _saveLater.ObjA = a
            _saveLater.ObjB = GetObjB(a);
            _saveLater.ObjC = GetObjC(a);   
        }

        _repo.SaveOrUpdate(listToBeSaved);
    }

    CreateOtherObjs(){
        if(_saveLater == null) return;

        Save(new List<ObjA> {_saveLater.ObjA}, new List<ObjB> {_saveLater.ObjB},
                _saveLater.Objc, _saveLater.ObjD);  //The original function posted
    }
}

Repo(){

  SaveOrUpdate(Dictionary<IEntity, SaveOrUpdate> objs){
    using (var session = GetSession()){
      using (var tx = session.BeginTransaction()) {
        try {
            foreach (var o in objs) {
                if (o.Key == null) continue;
                if (o.Value == SaveOrUpdate.Update)
                    session.Update(o.Key);
                else
                    session.Save(o.Key);
            }
            if (!tx.WasCommitted) {
                tx.Commit();
            }
        } catch (Exception) {
            if (tx != null) {
                tx.Rollback();
            }
            throw;
        }
      }
        }
    }


}

2 个答案:

答案 0 :(得分:0)

在我寻找一个更复杂的问题之前,比如一个电话卡在内存中或类似的东西我会把我的钱放在Save函数本身被多次触发。请注意,您注意到的唯一重复项是要保存的对象。更新可能会多次运行,因此没有可观察到的副作用。

是否从Web应用程序调用此方法?是否双击提交按钮?你可以通过添加一个日志记录机制来测试这个理论,并在调用Save方法时调用它以及调用它的参数。

答案 1 :(得分:0)

艾米,如果你看看发生了什么的最终结果,它会告诉你发生了什么。你传递的ObjA和它应该“创建”多个ObjB记录,并为每个唯一的ObjA创建1个ObjC记录。我猜你将ObjA与ObjB和ObjC联系在这个函数的范围之外,然后依靠save来保持这种变化。可以这样想,最终有许多不同的ObjB记录,其中一个外键返回到相同的ObjA记录,其中大多数都不正确。 由于某种原因,您的生产代码将ObjA与ObjB的相同Id和传递给此函数的ObjC相关联。在设置传递给函数的ObjA之前,关系代码甚至可以将它们关联起来。在调用保存之前,检查您对ObjA的新功能并记录关联代码。您可能需要考虑调用该服务的第三方供应商之一可能多次向您发送相同的数据。