baitianhai(hong) 说的对!做一个事务吧!

解决方案 »

  1.   

    事务是个好办法
    做个存储过程也不错。/*
    客户信息的写入或更新
    */
    CREATE PROCEDURE spCustomer
    @Name varchar (20),
    @age varchar (10),
     AS
    set nocount on
    declare @i int
    INSERT INTO Customers (name,age)       VALUES (@Name,@age)
    SELECT @i = @@IdentityINSERT INTO Orders(customerID)
                   VALUES(@i)
    GO
      

  2.   

    上面的代码在特定的情景下@i得到的值不是CustomerID,如果你使用的是SQL SERVER数据库,那使用Identity列时要非常小心。
    @@IDENTITY返回的是会话创建的最后一个identity值,在很多情景中,CustomerID不是会话最后创建的identity值,比如,接着上面的代码,你添加一个表table1和一个触发器trigger1:
    create table table1 (tableID int IDENTITY (1, 1) NOT NULL ,CustomerID int);
    create trigger trigger1 on Customers after insert
    as
    insert into table1 (CustomerID) select CustomerID from inserted;
    GO
    这时,你得到的@@IDENTITY是新创建的tableID,而不是你想得到的CustomerID,所以上面的代码这样写更好:CREATE PROCEDURE spCustomer
             @CustomerID int
    @Name varchar (20),
    @age varchar (10),
     AS
    select @CustomerID=Max(CustomerID)+1 from Customers;
    INSERT INTO Customers (CustomerID,name,age)       VALUES (@CustomerID,@Name,@age);INSERT INTO Orders(customerID)
                   VALUES(@CustomerID);GO
      

  3.   

    如果是在与数据源断开连接的状态下使用dataset时,应该在什么时候调用这个stored proc?
    客户完成一个下订单的过程后直接调用stored proc,然后再重新执行一次dataAdapter.Fill(DataSet)?使客户端的dataset和数据库保持同步?
      

  4.   

    Create a relation between the two DataTable's in DataSet on CustomerID and set up the right CustomerID, when you update DataSet, the database will fix the values for you
      

  5.   

    really? It's great! thanks a lot!
      

  6.   

    肯定有很多人做过下订单之类的程序。也就是数据库里有1:n关系的数据表。
    1,得有一个唯一标识一个记录的字段,通常是primary key字段,在sql server里可以用int identity,在access里用“自动编号"来定义。这个字段值在进行数据库insert操作时不用指定,数据库系统会自动生成该字段的值。(BULLSHIT)
    2,在购物网站上注册了一个id,数据库里肯定会有一个唯一标识你的字段,比如customerID,值是1002.当你在这个网站上下了n个订单时,订单表里可能的数据如下:
    customerID orderID
    1002       1998
    1002       2002
    1002       2009
    ...         ...
    这种情况下,customerID和orderID都是"自动编号“或int identity字段,实现起来也不会出什么问题。
    3。但是再看看另一种情况。一个医院的病人管理程序。
    假设有三个步骤:记录病人资料,记录证状,诊断,开药方。
    新病人来了,我们在dataset的病人记录DataTable里新加入一个DataRow,并把病人姓名,年龄等资料放进新建的DataRow里。病人看完病了,我们就要把他的症状,诊断,药方等信息输入到病历表中。问题是这时我们是在与数据源断开的dataset里的datatable里加入一个新记录,而不是在数据库里,在实际插入数据库之间我们无法知道sql server会为这个病人分配什么号(病人ID是int identity),那你到哪里找个病人id来插入到病历表(另一个DataTable)中啊?就算从数据库里取得max(病人id)再加上1,但是等到DataAdapter.update时,可能他的病人id值已经被别的机器上别的病人给占了。那么病历表中的数据就乱套了,
    废话很多,请原谅。
    请大家帮帮忙说说这种问题应该怎样处理?
      

  7.   

    you did not realize the power of ADO.NET yet, the trick is to add the relevant relations>>这个病人分配什么号?
    use an invalid ID, for example, the first new patient uses -1, the second new patient uses -2,.....
      

  8.   

    To nanhe0065(南赫) 
    你提到的医院的病人管理程序,我觉得在逻辑上有一些问题。
    假设病人到门诊登记,门诊将他的资料输入计算机,并打出一张门诊单(包含病人ID和门诊单ID)。门诊的操作是在界面中输入相关信息,然后必须提交数据库。如果他不提交数据库,就等于这张门诊单没有被确认,也就是不存在。
    从实际逻辑看,如果他不提交数据库,那么医生在作出诊断后,他就不可能找到门诊单上的病人ID和门诊单ID。很简单,我们不可能假设前一个操作者将他的操作结果放在自己机器的DataSet中(不提交数据库),而要另一个操作者到数据库里去找他的操作结果。关于客户机上的数据与服务器上的数据同步问题,你不需要重新执行一次dataAdapter.Fill(DataSet),拿identity为例,接着上面的例子:SqlCommand comm=new SqlCommand("spCustomer",conn);
    comm.CommandType=CommandType.StoredProcedure;
    comm.Parameters.Add(new SqlParameter("@CutomerID"),SqlDbType.Int,0,ParameterDirection.OutPut,false,0,0,"CutomerID"/*设置映射的数据源*/,DataRowVersion.Default,null);
    comm.Parameters.Add(new SqlParameter("@Name","名字"));
    comm.Parameters.Add(new SqlParameter("@age","年龄"));
    comm.UpdateRowSource=UpdateRowSource.OutputParameters;//执行命令时,输出参数被映射回数据行的源
    comm.ExecuteNonQuery();
      

  9.   

    如果存储过程中有语句
    INSERT INTO Customers (name,age)       VALUES (@Name,@age)SELECT @i = @@Identity From Customers
    这样应该是返回Customers表中最后增加一条记录的identity吧?
    会不会出现得到的@i不是刚插入的记录?(即在执行第一条插入语句后,其他程序也调用sp对表执行了插入操作)
      

  10.   

    to(saucer(思归))你的意思是不是说,在dataset中两个表建立了关系后,保存到数据库中去,这两个表中的数据就会根据要求存入到数据库中去??
      

  11.   

    to jhshen(沈还),@@Identity返回的是会话创建的最后一个Identity,你可以用查询分析器试验一下我上面给出的例子。
      

  12.   

    dy_2000_abc(芝麻开门):你可以用查询分析器试验一下我上面给出的例子;  jhshen(沈还): 即在执行第一条插入语句后,其他程序也调用sp对表执行了插入操作);我的看法:那就看你业务的性质拉,记录的频繁与否,出现的情形就是不一样........
      

  13.   

    DataTable: Customer                               DataTable: Record
    CustomerID (identity)<-add relation in DataSet--> CustomerID
    CustomName                                        Date
    ....                                              .....create a new Customer, set its
    CustomerID = -1create a new Record for this customer, set
    CustomerID = -1
    create another new Record for this customer, set
    CustomerID = -1
    ........
    create a new Customer, set its
    CustomerID = -2create a new Record for this customer, set
    CustomerID = -2
    ..............update the DataSet
    .............
      

  14.   

    to xuu27(乐者为王(xuu27)) and jhshen(沈还)
    我想你们可能误解这个例子了,例子返回的不是CustomerID,而是tableID。
      

  15.   

    @@identity返回的确实不一定是刚插入的customerID(int identity)值,比如像dy_2000_abc(芝麻开门)举的例子那样。
    create table table1 (tableID int IDENTITY (1, 1) NOT NULL ,CustomerID int);
    create trigger trigger1 on Customers after insert
    as
    insert into table1 (CustomerID) select CustomerID from inserted;
    GO
    这时@@identity返回的是触发器执行后的tableID值。
    dy_2000_abc(芝麻开门)举的例子
    CREATE PROCEDURE spCustomer
             @CustomerID int
    @Name varchar (20),
    @age varchar (10),
     AS
    select @CustomerID=Max(CustomerID)+1 from Customers;
    INSERT INTO Customers (CustomerID,name,age)       VALUES (@CustomerID,@Name,@age);INSERT INTO Orders(customerID)
                   VALUES(@CustomerID);GO
    存储过程里怎么有插入customerID的句子呢?customerID在sql server里是int identity字段啊。
    -------------------------------------------------------
    另外,芝麻开门说的对,我举的关于医院病人管理的例子确实有逻辑问题。
    但我们重新假设病人资料输入到开处方都在dataset里完成,最后统一地进行一次更新数据源。
    ————————————————————————————
    按思归的方案(我还没试过),如果在客户端dataset里建立病人资料表和病历表(1对多)之间的关系。给病人ID的DataColumn加上AutoIncrement属性
    等步骤,最后dataAdapter Update时数据库会不会自动正确处理呢?比如在dataset的病人表里新增的病人ID是3,插入到病历表中的病人ID也是3,但是等到dataAdapter Update时,sql server会自动处理这个问题?
      

  16.   

    The answer is yes! sql server会自动处理这个问题
      

  17.   

    I tested it! saucer, u r right!
    我碰到另外一个问题。
    在xml designer里定义二个表之间的关系后,很容易通过findbyXX,GetChildRows等来浏览子表,或定位母表。
    但是从SqlConnection到所有一切都是手工编程时,等到用DataRelation对象定义了两个表之间关系后,我就不知道该怎样访问子表了,不知道该怎样定位findbyXX,ChildRows.
    难道非得有那个该死的.xsd文件才能用上GetChildRows吗?
    myDataSet.Relations.Add(new DataRelaton("RelName",ParentTblPK,ChildTblFK));
    就死到这儿啦。思归是否用编码方式定义过二表之间关系后,再进行过相关表之间的浏览?
      

  18.   

    DataRow[] drChildList = ParentRow.GetChildRows("RelName");DataRow drParent = ChildRow.GetParentRow("RelName");
      

  19.   

    因为数据集内表的关系不是在xml designer(vstudio.net可视环境)下定义的,所以是非类型化数据集,通过非类型化数据集根本无法定位GetChildRows(也就是说在开发环境中打完ParentRow.后找不到GetChildRows),据说类型化数据集要有xml架构文件.xsd文件支持。看来除非对xml和xml架构等等非常明白,很难DIY这个问题。
      

  20.   

    as long as there is a relation, you can use GetChildRows to retrieve the rows from another table
      

  21.   

    天!你又说对了。GetChildRows和类型化或非类型化数据集倒没什么关系。但至少在非类型化数据集里是用不了
    DataRow da = myDataSet.myDataTable.findByOrderID(SelectedOrderID)
    这样的方法的吧。[类型化数据集先是从基DataSet类派生,然后使用XML架构文件(.xsd文件)中的信息生成新类。架构中的信息(表,列等)被作为一组第一类对象和属性生成并编译为此新数据集类。]思归,你有时间的话,找找VStudio.net帮助里的“演练:创建主控与明细Windows窗体“,如果不用xml架构文件,你看能不能像它那样通过数据绑定简单地处理。
      

  22.   

    “演练:创建主控与明细Windows窗体“中Form里左边是个listBox(显示Publishers表中的pub_name),右边是DataGrid(显示Title表),右边DataGrid控的DataMember竟然是两个DataTable的关系名(记得好像是Publishers.PublishersTitles),如果不是从Server Explorer里把表拖过来建的类型化数据集,这时怎么办呢?DataGrid.DataMember应该是什么值才能具有和演练同样的效果?
    还有,通过Server Explorer等步骤建立的数据集都能自动提供DataTable.findByPrimaryKeyColumnName(value)这样的方法来返回指定的ParentRow,再通过它来浏览子表。
    但是在一个没有.xsd架构文件为基础的数据集里怎样快速找到用户选定的ParentRow呢?
      

  23.   

    why are you so persistent on 类型化? read Type Safety in a Loosely Coupled World
    http://www.sellsbrothers.com/spout/#typeSafetyLooselyCoupled
      

  24.   

    谢谢芝麻开门及思归。
    Publishers表和Titles表的问题解决了。
    listBox.DataSource=myDataSet.Tables["Publishers"];
    listBox.DisplayMember="pub_name";DataGrid.DataSource=myDataSet.Tables["Publishers"];//这个也要指定为Publishers表,这个我当初没想到。
    DataGrid.DataMember = "PublishersTitles";//关系名。