Linq to sql 如何在LINQ中每次类层次结构更新时运行一次存储过程?
我的数据库中有两个相关的表:Page和Tag。一个页面可以与多个标记相关 无论何时修改这两个表中的任何一个,都需要执行名为BeforePageHierarchyUpdate的存储过程(在我的例子中,该存储过程在页面层次结构上执行一些日志记录和版本控制) 给我带来问题的是这两个要求:Linq to sql 如何在LINQ中每次类层次结构更新时运行一次存储过程?,linq-to-sql,Linq To Sql,我的数据库中有两个相关的表:Page和Tag。一个页面可以与多个标记相关 无论何时修改这两个表中的任何一个,都需要执行名为BeforePageHierarchyUpdate的存储过程(在我的例子中,该存储过程在页面层次结构上执行一些日志记录和版本控制) 给我带来问题的是这两个要求: 如果更新了页面实例或标记实例,则必须运行SP。但是,如果一个页面及其一个相关标记都被更新,则SP应该只被调用一次 存储过程必须包含在与其他LINQ语句相同的事务中。如果LINQ语句失败,则需要回滚存储过程。如果存储过
有人对如何实现这样的功能有什么想法吗?仅使用以下步骤更新这些表:
create procedure UpdatePageAndOrTag
(
@mode char(1) --"P"=page only, "T"=tag only, "B"=both
,@pageParam1 ...
,@pageParam2 ....
....
,@TagParam1.....
,@TagParam2....
....
)
as
EXEC BeforePageHierarchyUpdate
if @Mode="B" or @Mode="P"
Begin
update Page....
END
IF @Mode="B" or @Mode="T"
Begin
update tag...
END
return 0
go
在浏览了一些代码之后,这里是另一个选择。我对连接/事务代码是否正确并不完全满意(它大部分是从基本SubmitChanges实现反向工程的)
公共覆盖无效提交更改(System.Data.Linq.ConflictMode故障模式){
if(System.Transactions.Transaction.Current==null&&this.Transaction==null){
bool connectionOpened=false;
DbTransaction=null;
试一试{
if(this.Connection.State==ConnectionState.Closed){
this.Connection.Open();
连接开放=真;
}
事务=this.Connection.BeginTransaction(IsolationLevel.ReadCommitted);
这个。事务=事务;
提交更改前();
基本提交更改(故障模式);
Commit();
}
抓住{
if(事务!=null){
试一试{
transaction.Rollback();
}
抓住{
}
投
}
}
最后{
this.Transaction=null;
如果(连接打开){
this.Connection.Close();
}
}
}
否则{
提交更改前();
基本提交更改(故障模式);
}
}
提交更改前的私有无效(){
changesetchanges=this.GetChangeSet();
HashSet modifiedpage=新HashSet();
foreach(changes.Updates.OfType()中的页面){
修改页面。添加(页面。页面ID);
}
foreach(changes.Updates.OfType()中的PageTag标记){
modifiedpage.Add(tag.PageId);
}
foreach(changes.Inserts.OfType()中的PageTag标记){
//如果要插入父级,请不要运行更新SP。
如果(!changes.Inserts.Contains(tag.Page)){
modifiedpage.Add(tag.PageId);
}
}
foreach(changes.Deletes.OfType()中的PageTag标记){
//如果要删除父级,请不要运行更新SP。
如果(!changes.Deletes.Contains(tag.Page)){
modifiedpage.Add(tag.PageId);
}
}
foreach(修改页中的int pageId){
此.BeforePageHierarchyUpdate(pageId);
}
}
第三种可能的解决方案是将其放入repository类(或其他包装实现)中。这大大简化了事务代码,但该功能在DataContext层更合适
public class PageRepository : IPageRepository {
public void Save() {
using(TransactionScope trans = new TransactionScope()) {
BeforeSubmitChanges();
mDataContext.SubmitChanges();
trans.Complete();
}
}
private void BeforeSubmitChanges() {
ChangeSet changes = this.GetChangeSet();
HashSet<int> modifiedPages = new HashSet<int>();
foreach (Page page in changes.Updates.OfType<Page>()) {
modifiedPages.Add(page.PageId);
}
foreach(PageTag tag in changes.Updates.OfType<PageTag>()) {
modifiedPages.Add(tag.PageId);
}
foreach (PageTag tag in changes.Inserts.OfType<PageTag>()) {
//If the parent is being inserted, don't run the Update SP.
if (!changes.Inserts.Contains(tag.Page)) {
modifiedPages.Add(tag.PageId);
}
}
foreach (PageTag tag in changes.Deletes.OfType<PageTag>()) {
//If the parent is being deleted, don't run the Update SP.
if (!changes.Deletes.Contains(tag.Page)) {
modifiedPages.Add(tag.PageId);
}
}
foreach (int pageId in modifiedPages) {
this.BeforePageHierarchyUpdate(pageId);
}
}
}
公共类页面存储库:IPageRepository{
公共作废保存(){
使用(TransactionScope trans=new TransactionScope()){
提交更改前();
mDataContext.SubmitChanges();
trans.Complete();
}
}
提交更改前的私有无效(){
changesetchanges=this.GetChangeSet();
HashSet modifiedpage=新HashSet();
foreach(changes.Updates.OfType()中的页面){
修改页面。添加(页面。页面ID);
}
foreach(changes.Updates.OfType()中的PageTag标记){
modifiedpage.Add(tag.PageId);
}
foreach(changes.Inserts.OfType()中的PageTag标记){
//如果要插入父级,请不要运行更新SP。
如果(!changes.Inserts.Contains(tag.Page)){
modifiedpage.Add(tag.PageId);
}
}
foreach(changes.Deletes.OfType()中的PageTag标记){
//如果要删除父级,请不要运行更新SP。
如果(!changes.Deletes.Contains(tag.Page)){
modifiedpage.Add(tag.PageId);
}
}
foreach(修改页中的int pageId){
此.BeforePageHierarchyUpdate(pageId);
}
}
}
如果我需要更新与单个页面相关联的多个标记,该怎么办?传入一个“数组”(逗号分隔列表)字符串并在存储过程中拆分它:,我喜欢这种方法:,您可以将插入的SELECT FROM中的多个参数拆分到临时表中,然后从中使用集合。你可以问另一个关于使用多个逗号分隔的列表参数的问题,并得到很多关于这方面的信息。如何使用LINQ的更改跟踪来实现这一点?还是必须显式地调用它?不管是好是坏,这是我目前正在使用的实现。如果我改变主意,我会尽量记住更新这个问题。
public class PageRepository : IPageRepository {
public void Save() {
using(TransactionScope trans = new TransactionScope()) {
BeforeSubmitChanges();
mDataContext.SubmitChanges();
trans.Complete();
}
}
private void BeforeSubmitChanges() {
ChangeSet changes = this.GetChangeSet();
HashSet<int> modifiedPages = new HashSet<int>();
foreach (Page page in changes.Updates.OfType<Page>()) {
modifiedPages.Add(page.PageId);
}
foreach(PageTag tag in changes.Updates.OfType<PageTag>()) {
modifiedPages.Add(tag.PageId);
}
foreach (PageTag tag in changes.Inserts.OfType<PageTag>()) {
//If the parent is being inserted, don't run the Update SP.
if (!changes.Inserts.Contains(tag.Page)) {
modifiedPages.Add(tag.PageId);
}
}
foreach (PageTag tag in changes.Deletes.OfType<PageTag>()) {
//If the parent is being deleted, don't run the Update SP.
if (!changes.Deletes.Contains(tag.Page)) {
modifiedPages.Add(tag.PageId);
}
}
foreach (int pageId in modifiedPages) {
this.BeforePageHierarchyUpdate(pageId);
}
}
}