迭代添加多表记录问题:AutoCAD点转圆二次开发报错
AutoCAD二次开发:点转圆的问题解决
问题分析
你编写的点转圆程序遇到两个核心问题:
- 迭代创建圆时,调用
AppendEntity生成第一个圆后抛出eAlreadyInDb异常 - 当前使用两个事务分别读取点和创建圆,不确定是否为最优方案
异常原因
你在循环外仅创建了一个Circle对象实例,第一次调用AppendEntity后,该对象已被添加到AutoCAD数据库中。第二次循环时再尝试将同一个对象添加到数据库,就会触发eAlreadyInDb异常——每个DBObject实例只能被添加到数据库一次。
事务效率问题
使用两个事务并非最高效方案。事务的开启、提交都有性能开销,读取点和创建圆的操作可以在同一个事务内完成,避免重复的事务管理开销。
修复后的代码
using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; [CommandMethod("PointsToCircles")] public void PointsToCircles() { Document adoc = Application.DocumentManager.MdiActiveDocument; Database adb = adoc.Database; Editor acDocEd = adoc.Editor; List<Point3d> vlist = new List<Point3d>(); // 合并为单个事务,同时处理读取点和创建圆 using (Transaction trans = adb.TransactionManager.StartTransaction()) { // 读取块表 BlockTable acBlkTbl = trans.GetObject(adb.BlockTableId, OpenMode.ForRead) as BlockTable; // 选择点对象的过滤器 TypedValue[] acTypValAr = new TypedValue[1]; acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "POINT"), 0); SelectionFilter acSelFtr = new SelectionFilter(acTypValAr); PromptSelectionResult acSSPrompt = acDocEd.GetSelection(acSelFtr); if (acSSPrompt.Status == PromptStatus.OK) { SelectionSet acSSet = acSSPrompt.Value; Application.ShowAlertDialog("选中的POINT数量: " + acSSet.Count.ToString()); // 收集选中点的坐标 foreach (SelectedObject acSSObj in acSSet) { if (acSSObj != null) { DBPoint acDBP = trans.GetObject(acSSObj.ObjectId, OpenMode.ForRead) as DBPoint; vlist.Add(acDBP.Position); } } // 打开模型空间用于写入 BlockTableRecord acBlkTblRec = trans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord; // 循环创建圆:每次循环实例化新的Circle对象 foreach (Point3d centerPoint in vlist) { Circle acCirc = new Circle(); acCirc.Center = centerPoint; acCirc.Radius = 12.00; acBlkTblRec.AppendEntity(acCirc); trans.AddNewlyCreatedDBObject(acCirc, true); } } else { Application.ShowAlertDialog("选中的POINT数量: 0"); } // 提交事务 trans.Commit(); } }
关键修改点
- 解决
eAlreadyInDb异常:将Circle acCirc = new Circle();移到循环内部,每次迭代创建一个新的Circle实例,确保每个圆对象都是独立的,仅被添加到数据库一次。 - 优化事务效率:将读取点和创建圆的逻辑合并到同一个事务中,减少事务开启/提交的开销,提升程序运行效率。
- 简化代码:使用
foreach遍历点列表,代码更简洁易读。
内容的提问来源于stack exchange,提问作者dengebre
相关产品推荐
相关产品推荐

