在同一事务中删除和添加子实体会使nhibernate混淆

时间:2014-01-20 14:04:17

标签: c# nhibernate unit-of-work ncommon

我收到了经典错误:

'deleted object would be re-saved by cascade 
(remove deleted object from associations)[DrillingContracts.Domain.TrackedField#3216' 

但是有一个额外的转折,错误的起源完全是因为我正在删除一个实体并添加一个新实体。

我用这种方法清空所有已存在的孩子

 public void RemoveChildren(TrackedNode parentNode)
        {
            foreach (TrackedField trackedField in parentNode.ChildNodes)
            {
                _trackedFieldRepository.Delete(trackedField);
                parentNode.RemoveChildNode(trackedField);
            }
        }

然后立即添加新的

public virtual void AddTrackedChildFieldsToTrackedCell(
        params TrackedField[] nodes)
    {
        foreach (var field in nodes)
        {
            if (IsPath(field.Name))
            {
                throw new InvalidTrackedFieldNameException(
                    "The value " + field.Name + " is not a valid tracked field name.");
            }
                field.Supplement = this;
                _trackedFields.Add(field);
        }
    }

对于那些想知道存储库中发生了什么的人,我得到的最佳答案就是魔术。 10,000%魔法。最初的开发人员使用NCommon。这两个方法都是从NCommon.UnitOfWork属性中包含的方法调用的。

应该注意,每种方法都按预期执行。 (IE,没有字段可以删除添加作品,同样,没有字段可以添加删除作品。)

修改

[HttpPost]
[UnitOfWork(Scope = FilterScope.Result)]
public ActionResult SaveEditMode(long id, AddTrackedRowViewModel model, string editMode, List<string> elementNames, string provisionData)
        {
            var supplement = _supplementCoordinator.GetSupplement(id);
            var table = supplement.TrackedTables.First(x => x.Name == model.Name);

                var valueAttributes = JsonSerializer.DeserializeFromString<List<ValueAttributeViewModel>>(provisionData);
                foreach (var prop in valueAttributes)
                {
                    supplement.Set(prop.Attribute, prop.Value, false);
                }

                var cell = table.TrackedRows.First(x => x.Ordinal == model.Ordinal).TrackedCells.First(x => x.Name == "Detail");
                _supplementCoordinator.RemoveChildren(cell);

                if (elementNames != null)
                {
                    var childNodes = elementNames.Select((t, i) => new TrackedField(cell, t, i)).ToList();
                    supplement.AddTrackedChildFieldsToTrackedCell(childNodes.ToArray());
                }


                return SwitchEditMode(model, editMode, table);
        }

答案

public void AddChildren(Supplement supplement, TrackedNode parentNode, params TrackedField[] nodes)
    {
        foreach (TrackedField trackedField in nodes)
        {
            parentNode.AddChildNode(trackedField);

        }
        supplement.AddTrackedChildFieldsToTrackedCell();
    }

我没有将它们添加为父节点的新权限,只是相关的补充。

1 个答案:

答案 0 :(得分:1)

只是为了完整。消息'已删除的对象将被重新保存..'是由显式调用session.Delete(instance)引起的。

在这种情况下,我们只需要1)从旧的父集合中删除这样的项目,然后2)将它附加到新的父项。级联映射和session.Flush()将正确地更新DB。

最后注意事项:这样的“移动”必须在一个会话/事务中完成,以避免其他问题(例如'Row被另一个事务更新或删除......')。