cad.net 事务处理

读取图元

using var tr = db.TransactionMananger.StartTransaction();
var ent = (Entity)tr.GetObject(id, OpenMode.ForMode);
// 查询图元的任务...略...

// 修改图元前需要提权:
ent.UpgradeOpen();

// 降权语句是无效的
ent.DowngradeOpen();

提权就是写模式,
一旦提权之后,会发现 ent.IsWriteEnable == true
即使通过降权也不能重新改为false的,所以这个降权是无效的.

以下都是猜测:
1,Acad事务会用一个队列来记录每个tr.GetObject()的对象.
这个队列容器是tr.GetAllObject()
2,事务队列需要这个标记ent.IsWriteEnable来判断是否写入数据库.
如果你写入了,然后降权了,它就不知道这个是"写入"还是"放弃"了.
一旦写模式就不能读模式.
其实是桌子偷懒了,不想通过剔除来改变容器.

所以我们更多时候需要这样做:
读模式打开图元,查询条件满足之后,才提权到写模式.
这样可以避免不必要的写入判断.

此处有群友克隆说明要dowm的例子,我没有测试.
https://www.cnblogs.com/JJBox/p/10713005.html

记录IFox的事务错误

IFox利用了自己的事务栈来管理的事务,事务栈是记录在静态字段上,
使得事务的生命无限延长,通过using来释放并自动提交.
子函数是通过DBTrans.Top获取栈顶事务,就不用传参了.

但是IFox前期版本的栈空就直接创建了,
这样导致了命令结束了也不会释放事务,
令到ctrl+z直接回滚到上个事务,也可能导致虽显但无法选择图元,
所以我在Top上面加了一个报错,
栈空的时候必须要用户先创建事务:using DBTrans tr = new();

请使用IFox的事务栈
https://gitee.com/inspirefunction/ifoxcad

引起undo撤回错误的代码

报错0x01

!dbenti.cpp@3310:eWasErased错误

引起错误的代码:
img

好的代码:
img
(这段代码的两个事务是单独的事务,没有被另一个大的事务包裹,是好的代码)

原理
两段代码仅仅是事务提交的方式不同,
这两段代码顺序执行都不会引起任何错误,但是 ctrl+z 回滚操作时候右边却会引起

引起错误的原因是:
ctrl+z 撤回操作会根据事务进行回滚,如果一起回滚,
那么回滚的时候会先按照处理的图元回滚图层,
但是此时因为图层的删除还没有恢复,缺少图层的记录,

所以将他们分层两个事务,回滚操作就会先恢复图层,再进行回滚图元的修改.

报错0x02

0x6B00500A (msvcr80.dll)处(位于 acad.exe 中)引发的异常: 0xC0000005: 写入位置 0xFFE00000 时发生访问冲突。
操作时候仍然是顺序执行没有问题,但是使用了ctrl+z就出现,此报错原理不明,大家可以尽情猜测.

引起错误的代码:生成四叉树所有节点边界
生成十万个数量的矩形,因为多段线的数据量大,因此引起了这个错误.

db.Action(tr => {
    foreach (var item in nodeRects)
    {
        var pts = item.ToPoints();
        var rec = EntityAdd.AddPolyLineToEntity(pts.ToPoint2d());
        rec.ColorIndex = 250;
        tr.AddEntityToMsPs(db, rec);
    }
});

好的代码
解决方案依然是将事务拆分到循环体内部

foreach (var item in nodeRects)//Count = 97341 当数量接近这个量级
{
    db.Action(tr => {
        var pts = item.ToPoints();
        var rec = EntityAdd.AddPolyLineToEntity(pts.ToPoint2d());
        rec.ColorIndex = 250;
        tr.AddEntityToMsPs(db, rec);
    });
}

验证事务Abort

public class CmdTest_Tr {
    static ObjectId? objectId;
    static Handle? handle;
    [CommandMethod("CmdTest_TryAbort1", CommandFlags.DocExclusiveLock)]
    public void CmdTest_TryAbort1()
    {
        var dm = Acap.DocumentManager;
        var doc = dm.MdiActiveDocument;
        var db = doc.Database;
        var ed = doc.Editor;
        ed.WriteMessage("\n测试cad事务1");

        using (var tr = db.TransactionManager.StartTransaction())
        {
            var line = new Line(Point3d.Origin, new Point3d(1000, 1000, 0));
            objectId = tr.AddEntityToMsPs(db, line);//https://www.cnblogs.com/JJBox/p/14300098.html
            handle   = line.Handle;

            //为了测试自动释放不是等于下句....经过测试,写不写都一样的!
            //tr.Abort();//撤销
        }
    }

    [CommandMethod("CmdTest_TryAbort2", CommandFlags.DocExclusiveLock)]
    public void CmdTest_TryAbort2()
    {
        var dm = Acap.DocumentManager;
        var doc = dm.MdiActiveDocument;
        var db = doc.Database;
        var ed = doc.Editor;
        ed.WriteMessage("\n测试cad事务2");

        if (handle == null)
            ed.WriteMessage("\n句柄 空啊");// (handent "1DE") 获取句柄图元名,如果是IsErased那么这里返回nil
        var id2 = handle.Value.TryGetObjectId(db);
        if (id2 == ObjectId.Null)
            ed.WriteMessage("\nid2 空啊");
        else
        {
            ed.WriteMessage($"\nid2 不空啊,id.IsErased:{objectId.Value.IsErased}");
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var ent = objectId.Value.ToEntity(tr);
                if (ent == null)
                    ed.WriteMessage("图元是空的");
                else
                    ed.WriteMessage("图元是不空的");
            }
        }

        if (objectId == null)
            ed.WriteMessage("\nid 空啊");
        else
        {
            ed.WriteMessage($"\nid 不空啊,id.IsErased:{objectId.Value.IsErased}");
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var ent = objectId.Value.ToEntity(tr);
                if (ent == null)
                    ed.WriteMessage("图元是空的");
                else
                    ed.WriteMessage("图元是不空的");
            }
        }
    }
}

相关阅读

cad.net undo返回操作

posted @   惊惊  阅读(1076)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示