我有一个页面,我使用两个ASP DetailsView
控件来呈现来自两个不同但相关的LinqDataSource
对象的数据。我的主表在第一个DetailsView / LinqDataSource集中表示,我使用LinqDataSource的内置更新功能在DetailsView处于编辑模式时保持更改。这里的主要表格代表“联系”实体(即个人或组织及其联系信息)。
第二个DetailsView呈现来自交叉引用表的数据,该表将联系人与一个或多个“标记”相关联。标签定义来自另一个表,因此交叉引用表只是将联系人ID与标签ID相关联;标准的多对多类型场景。
我对Tag Xref的更新工作正常;在联系人中添加或删除标记时,会从外部参照表中插入或删除相应的行。这不是通过LinqDataSource完成的,而是通过处理标签DetailsView的ItemUpdating
事件并使用DataContext手动处理插入和删除。
因此,联系人和联系人的标签可以单独更新。麻烦的是,我需要在单个事务中一起更新Contact和Tags Xref。我将两个DetailsView控件链接起来,这样当用户单击第一个控件的“Update”时,它会触发第二个控件的更新。但是第一个DetailsView使用其绑定的LinqDataSource来执行更新,该更新具有自己的DataContext。尝试在我的手动更新和LinqDataSource之间“共享”DataContext会导致ObjectDisposed异常。
我觉得我错过了一些明显的东西。共享DataContext对象看起来像一个滑坡。有没有办法在页面上运行一个包含两个操作的事务?
答案 0 :(得分:3)
你有正确的方法。在页面生命周期的早些时候创建一个DataContext对象(我通常使用构造函数)。向LinqDataSource
个myDataContext.Connection.Open();
myDataContext.Transaction = myDataContext.Connection.BeginTransaction();
添加ContextCreating处理程序。在处理程序中,将DataContext分配给事件的ObjectInstance属性(另请参阅:this answer)。例如,在ItemUpdating事件中创建交易:
LinqDataSource
现在,这是一个棘手的步骤 - 你之前被绊倒了。默认情况下,ContextCreating
将在完成提交更改后处置其DataContext。您需要通过添加ContextDisposing事件处理程序来覆盖此行为。在处理程序中,将事件的Cancel属性设置为true。
现在工作完成后,您可以提交或回滚事务。 (不要忘记处理事务。)最后,您可以在Page_Unload中处理DataContext。
P.S。如果您使用的是DynamicData,请注意DynamicDataManager将自己的处理程序添加到创建 new DataContext的Complete
,从而避免显式创建的事务。烦。
或者,您可以使用TransactionScope。只需在工作完成之前创建一个新对象,然后在工作完成后调用{{1}}。尽管如此,我的品味还有太多的魔力。我尽可能使用更明确的DataContext事务。