Linq to SQL跨DBContext删除记录报错,能否实现跨上下文删除?
解决Linq to SQL跨DBContext删除记录的问题
问题原因
你遇到的Cannot remove an entity that has not been attached.错误,本质是Linq to SQL的实体实例与创建它的DBContext强绑定——新的DBContext无法识别来自另一个上下文的实体,自然不允许对其执行删除操作。
可行解决方案
以下几种方法无需修改GetDatabaseRecordByID的签名,即可实现跨上下文删除:
1. 将现有实体附加到新DBContext后删除
直接将从旧上下文获取的实体附加到新上下文,让新上下文识别它,再执行删除:
var record = GetDatabaseRecordByID(UniqueObjectID); if (record != null) { using (var db = new DBContext()) { var targetTable = db.GetTable(typeof(T2)); // 将实体附加到当前上下文 targetTable.Attach(record); targetTable.DeleteOnSubmit(record); db.SubmitChanges(); } }
注意:如果实体包含关联的子实体或未同步的状态变更,可能引发冲突,适合实体结构简单、无关联数据的场景。
2. 通过主键在新DBContext中查询后删除
跳过跨上下文传递实体,直接在新上下文里用主键查询目标记录再删除,这是最稳妥的方案:
var record = GetDatabaseRecordByID(UniqueObjectID); if (record != null) { using (var db = new DBContext()) { var entityToDelete = db.GetTable(typeof(T2)).Cast<T2>() .FirstOrDefault(x => x.ID == UniqueObjectID); // 替换为你的主键字段 if (entityToDelete != null) { db.GetTable(typeof(T2)).DeleteOnSubmit(entityToDelete); db.SubmitChanges(); } } }
优点:完全避免上下文状态冲突,兼容性最好;缺点是多一次数据库查询。
3. 创建仅含主键的虚拟实体进行删除
如果不想额外查询数据库,可以创建一个仅填充主键的实体实例,附加到新上下文后删除:
var record = GetDatabaseRecordByID(UniqueObjectID); if (record != null) { using (var db = new DBContext()) { var dummyEntity = Activator.CreateInstance<T2>(); dummyEntity.ID = UniqueObjectID; // 替换为你的主键字段 var targetTable = db.GetTable(typeof(T2)); targetTable.Attach(dummyEntity); targetTable.DeleteOnSubmit(dummyEntity); db.SubmitChanges(); } }
优点:无需额外查询,效率高;缺点是需要明确实体的主键字段,适合主键单一且明确的场景。
内容的提问来源于stack exchange,提问作者Tom Gullen
相关产品推荐
相关产品推荐

