ObjectDataSourc用法之八(并发控制)

在进行数据库的操作中,更新和删除操作可能会引起冲突:
假设有A,B两个人同时取到如下表中的一行元组值:
 id    书名(varchar(max))        是否过期(bit)
 7   《c#开发》                       1
可以看到当AB两人取到的这个记录是id:7,书名:《c#开发》,是否过期:1(1表示过期了,0表示没过期)
现在A觉得这本书过期了要将这条记录删除掉,B因为发现这本书应该是没有过期的想立即将其是否过期设置为0
由于B手脚快些所以先执行了update,现在数据库中这条记录应该是:
 id    书名(varchar(max))        是否过期(bit)
 7   《c#开发》                       0
但是A看到的还是
 id    书名(varchar(max))        是否过期(bit)
 7   《c#开发》                       1
所以A就执行了delete命令将这条记录删除了
那么事实上A就将一本不该删除的书删除了
犯下这种错误既不能怪A,也不能怪B,是因为A看到的并不是最新的信息,设想如果在A进行delete操作之前,将这条记录从数据库检索出来,在和A刚开始看到这条记录时候的值进行对比,如果值发生了变化有取消删除操作,没有改变再进行执行delete,就不会发生这种悲剧

这就要求对程序进行并发控制,而ObjectDataSource为我们提供了并发控制机制:

ObjectDataSource 控件有一个属性ConflictDetection , 叫做冲突检测.  可以设置再应用程序中如何处理并发冲突.
ConflictDetection 有两个可选值:

默认设置为OverwriteChanges 这是最小化的并发冲突设置,在更新和删除的时候不会提供原始数据信息,无法进行并发控制.  
CompareAllValues 这将给予你最大的灵活性,它将在更新和删除的时候提供原始的数据信息,所以可以进行并发控制
请看如下示例:
用于ObjectDataSource的实体对象类:

public class Student
{
    
private int _id;
    
public string _name;
    
private int _age;
    
private bool _sex;

    
public int Id
    {
        
set
        {
            _id 
= value;
        }
        
get
        {
            
return _id;
        }
    }

    
public string Name
    {
        
set
        {
            _name 
= value;
        }
        
get
        {
            
return _name;
        }
    }

    
public int Age
    {
        
set
        {
            _age 
= value;
        }
        
get
        {
            
return _age;
        }
    }

    
public bool Sex
    {
        
set
        {
            _sex 
= value;
        }
        
get
        {
            
return _sex;
        }
    }

    
public Student()
    {

    }
}


ObjectDataSource和GridView的设置:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="ObjectDataSource1" AllowPaging="True" PageSize="5" AllowSorting="True" DataKeyNames="Id">
            
<Columns>
                
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
                
<asp:BoundField DataField="Id" HeaderText="Id" SortExpression="Id" />
                
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
                
<asp:BoundField DataField="Age" HeaderText="Age" SortExpression="Age" ReadOnly="true" />
                
<asp:CheckBoxField DataField="Sex" HeaderText="Sex" SortExpression="Sex" />
            
</Columns>
        
</asp:GridView>
        
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="DeleteStudent"
            SelectMethod
="GetPageStudent" TypeName="StudentDAL" UpdateMethod="UpdateStudent" OldValuesParameterFormatString="old_{0}" EnablePaging="True" MaximumRowsParameterName="size" SelectCountMethod="GetAllCount" StartRowIndexParameterName="start" SortParameterName="order" InsertMethod="InsertStudent" DataObjectTypeName="Student" >
            
<InsertParameters>
                
<asp:Parameter Name="Name" Type="String" />
                
<asp:Parameter Name="Age" Type="Int32" />
                
<asp:Parameter Name="Sex" Type="Boolean" />
            
</InsertParameters>
            
<UpdateParameters>
                
<asp:Parameter Name="s" Type="Object" />
                
<asp:Parameter Name="old_s" Type="Object" />
            
</UpdateParameters>
        
</asp:ObjectDataSource>
        
<asp:Button ID="btnAdd" runat="server" OnClick="btnAdd_Click" Text="Add" />


然后是最关键的!后台供ObjectDataSource调用的DAL层次代码:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// StudentDAL 的摘要说明
/// </summary>
public class StudentDAL
{
    
string conn = "Data Source=localhost;Initial Catalog=qy;Integrated Security=True";
    SqlConnection oConn;
    SqlCommand oCommand;

    
public StudentDAL()
    {
        oConn 
= new SqlConnection(conn);
        oCommand 
= new SqlCommand();
    }

    
public int GetAllCount()
    {
        oConn.Open();
        oCommand.Connection 
= oConn;
        oCommand.CommandText 
= "select count(*) as T from Test_Student";
        
int count=Convert.ToInt32(oCommand.ExecuteScalar());
        oConn.Close();

        
return 50;
    }


    
public List<Student> GetPageStudent(int start,int size,string order)
    {
        oConn.Open();
        oCommand.Connection 
= oConn;
        oCommand.CommandText 
= "select * from Test_Student";
        DataTable dt 
= new DataTable();
        SqlDataAdapter sda 
= new SqlDataAdapter(oCommand);
        sda.Fill(dt);
        oConn.Close();

        List
<Student> students = new List<Student>();
        
int i;
        
for (i = 0; i < dt.Rows.Count; i++)
        {
            Student s 
= new Student();
            s.Id 
= Convert.ToInt32(dt.Rows[i]["ID"]);
            s.Name 
= dt.Rows[i]["Name"].ToString();
            s.Age 
= Convert.ToInt32(dt.Rows[i]["Age"]);
            s.Sex 
= Convert.ToBoolean(dt.Rows[i]["Sex"]);
            students.Add(s);
        }

        
return students;
    }

    
public void InsertStudent(Student s)
    {
        oConn.Open();
        oCommand.Connection 
= oConn;
        
string sql = "insert into Test_Student(Name,Age,Sex) values('" + s.Name + "'," + s.Age.ToString() + "," + Convert.ToInt32(s.Sex) + ")";
        oCommand.CommandText 
= sql;
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }

    
public void InsertStudent(string Name,int Age,bool Sex)
    {
        oConn.Open();
        oCommand.Connection 
= oConn;
        
string sql = "insert into Test_Student(Name,Age,Sex) values('" + Name + "'," + Age.ToString() + "," + Convert.ToInt32(Sex) + ")";
        oCommand.CommandText 
= sql;
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }


    
public void UpdateStudent(Student s)//在DataObjectType模式下,ConflictDetection= Overwrite Changes的时候,只需要传入一个Student,来进行更新
    {
        oConn.Open();
        oCommand.Connection 
= oConn;
        
string sql = "update Test_Student set Name='" + s.Name + "',Age=" + s.Age.ToString() + ",Sex=" + Convert.ToInt32(s.Sex) + " where id=" + s.Id.ToString();
        oCommand.CommandText 
= sql;
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }


    
public void UpdateStudent(Student s, Student old_s)//在DataObjectType模式下,ConflictDetection=CompareAllValues需要两个Student,一个叫s里边记录了更新的字段信息,另外个叫old_s(这个对象名是根据ObjectDataSource的OldValuesParameterFormatString设置的格式old_{0})记录了原始的字段信息,然后比较两个Student对象进行冲突检测
    {
        //冲突检测逻辑.....略
        int Age = 0;
        oConn.Open();
        oCommand.Connection 
= oConn;
        
string sql = "update Test_Student set Name='" + s.Name + "',Age=" + Age.ToString() + ",Sex=" + Convert.ToInt32(s.Sex) + " where id=" + s.Id.ToString();
        oCommand.CommandText 
= sql;
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }

    
public void UpdateStudent(int old_Id, string Name, bool Sex, int Id, int Age)//ObjectDataSource在ConflictDetection= Overwrite Changes的时候要求只把现在更新的字段,以及原来的主键字段old_{DataKeyName}(这个名字是根据ObjectDataSource的OldValuesParameterFormatString设置的格式old_{0})传进来,以便索引到更新行
    {
        oConn.Open();
        oCommand.Connection 
= oConn;
        oCommand.CommandText 
= "update Test_Student set Name='" + Name + "',Age=" + Age.ToString() + ",Sex=" + Convert.ToInt32(Sex).ToString() + " where id=" + old_Id.ToString();
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }

    
public void UpdateStudent(int old_Id, string Name, bool Sex, int Id, int Age, string old_Name, bool old_Sex, int old_Age)//ObjectDataSource在ConflictDetection= CompareAllValues的时候要求把现在更新的字段,以及原来的字段old_{0}(这个名字是根据ObjectDataSource的OldValuesParameterFormatString设置的格式old_{0})都传进来,以便进行冲突检测,然后再更新
    {
        //冲突检测逻辑.....略
        oConn.Open();
        oCommand.Connection 
= oConn;
        oCommand.CommandText 
= "update Test_Student set Name='" + Name + "',Age=" + Age.ToString() + ",Sex=" + Convert.ToInt32(Sex).ToString() + " where id=" + old_Id.ToString();
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }

    
public void DeleteStudent(Student s)//在DataObjectType模式下,ConflictDetection= Overwrite Changes/CompareAllValues只需要一个Student就可以了,因为传过来的记录本来就含有删除字段的所有属性,可以进行冲突检测
    {
        //冲突检测逻辑.....略
        oConn.Open();
        oCommand.Connection 
= oConn;
        oCommand.CommandText 
= "delete from Test_Student where id=" + s.Id.ToString();
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }

    
public void DeleteStudent(int old_Id)//ObjectDataSource在ConflictDetection= Overwrite Changes的时候只会把old_{DataKeyName}的字段传进来,所以GridView如果没有设置DataKeyName,那么参数就不会传进来,也无法执行删除的sql语句
    {
        oConn.Open();
        oCommand.Connection 
= oConn;
        oCommand.CommandText 
= "delete from Test_Student where id=" + old_Id.ToString();
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }

    
public void DeleteStudent(int old_Id, string old_Name, bool old_Sex, int old_Age)//ObjectDataSource在ConflictDetection= CompareAllValues的时候要求把现在更新的字段,以及原来的字段old_{0}都传进来,以便进行冲突检测
    {
        //冲突检测逻辑.....略
        oConn.Open();
        oCommand.Connection 
= oConn;
        oCommand.CommandText 
= "delete from Test_Student where id=" + old_Id.ToString();
        oCommand.ExecuteReader(CommandBehavior.CloseConnection);
    }
}
原文地址:https://www.cnblogs.com/OpenCoder/p/1568747.html