0

以下是我正在使用的相关技术:

  • Devart 的 dot Connect for Oracle(为 Oracle 提供方便的 Linq-to-Sql)。
  • 强类型 ADO.NET 数据集。
  • 一个甲骨文数据库。

这是挑战:

  • 我的旧代码使用 ADO.NET 数据集和表适配器提交数据库更新。
  • 我想开始将该代码转换为 Linq-to-Sql,但我想零敲碎打地做,以尽量减少代码流失和风险。

这是我的概念验证模式:

父表

  • 父代号
  • 父母名字

子表

  • 孩子.Id
  • Child.ParentId
  • 子名

这是我的概念验证代码块:

using System;
using System.Data.Common;
using DevArtTry1.DataSet1TableAdapters;

namespace DevArtTry1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (DataContext1 dc = new DataContext1())
            {
                dc.Connection.Open();
                using (DbTransaction transaction = dc.Connection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    dc.Transaction = transaction;

                    Parent parent = new Parent();
                    parent.Id = 1;
                    parent.Name = "Parent 1";
                    dc.Parents.InsertOnSubmit(parent);
                    dc.SubmitChanges(); // By virtue of the Parent.Id -> Child.ParentId (M:N) foreign key, this statement will impose a write lock on the child table.

                    DataSet1.CHILDDataTable dt = new DataSet1.CHILDDataTable();
                    DataSet1.CHILDRow row = dt.NewCHILDRow();
                    row.ID = 1;
                    row.PARENTID = 1;
                    row.NAME = "Child 1";
                    dt.AddCHILDRow(row);

                    CHILDTableAdapter cta = new CHILDTableAdapter();
                     // cta.Transaction = transaction;  Not allowed because you can't convert source type 'System.Data.Common.DbTransaction to target type 'System.Data.OracleClient.OracleTransaction.
                    cta.Update(dt); // The thread will encounter a deadlock here, waiting for a write lock on the Child table.
                    transaction.Commit();
                }
            }

            Console.WriteLine("Successfully inserted parent and child rows.");
            Console.ReadLine();
        }
    }
}

  • 正如上面的注释所示,线程将在子数据适配器的更新调用上无限期地停止,因为它将无限期地等待子表上的写锁定。【注意外键关系:Parent.Id -> Child.ParentId (M:N)】

这是我的问题:

  • 我想将整个代码块包装在一个事务中。
  • 我可以这样做吗?考虑到:
    • 我想使用 Linq-to-Sql 的SubmitChanges 方法在父表上提交更新...
    • 我想使用 ADO.NET 数据集表适配器对 Child 表进行更新。

这里有两个有趣的脚注:

  1. 这整个事情相反的。也就是说,如果我想使用数据适配器提交对父表的更改并使用 linq-to-sql... 提交对子表的更改,那将起作用
  2. 我尝试将事务显式附加到数据适配器,但编译器不允许这样做,因为它是不同类型的事务。

                    CHILDTableAdapter cta = new CHILDTableAdapter();
                cta.Transaction = transaction; // Not allowed because you can't convert source type 'System.Data.Common.DbTransaction' to target type 'System.Data.OracleClient.OracleTransaction'.
                cta.Update(dt);
                transaction.Commit();
    
4

3 回答 3

1

我对甲骨文的交易一无所知......但在 dotnet 方面,您应该可以自己控制交易。确保两种技术都使用相同的连接实例。

当我们通过连接而不是通过 ORM 控制事务时,我们使用事务范围:http: //msdn.microsoft.com/en-us/library/ms172152.aspx

于 2009-05-20T14:51:08.507 回答
1

我有同样的问题,遇到这两个错误:

  • 违反完整性约束 (ORA-02291)
  • “如果密钥不是数据库生成的,则无法插入具有相同密钥的实体”

问题是子对象的标识列设置不正确。如果 DotConnect LINQ 不假定身份密钥,则对象属性似乎是临时设置的,从而导致非顺序更新,从而导致完整性违规。

这是修复:

  • LINQ 需要知道孩子的主键是实体键并且是自动生成的。
  • 在 Oracle 中,为子对象设置一个自动递增的键。
  • 首先创建一个序列:

      DROP SEQUENCE MyChild_SEQ;
      CREATE SEQUENCE MyChild_SEQ
          MINVALUE 1
          MAXVALUE 999999999999999999999999999
          START WITH 1
          INCREMENT BY 1
          CACHE 20;
    
  • 接下来创建 OnInsert 触发器:

    CREATE OR REPLACE TRIGGER MyChild_AUTOINC 
    BEFORE INSERT
    ON MyChildObject
    FOR EACH ROW
    BEGIN
      SELECT MyChild_SEQ.nextval
      INTO :NEW.MyChild_ID
      FROM dual;
    END MyChild_AUTOINC ; 
    ALTER TRIGGER MyChild_AUTOINC ENABLE
    
  • 修改存储模型以合并新的自动生成的主键:

    • 在 dotConnect 的 EntityDeveloper 中,打开您的 LINQ 存储模型(.LQML 文件)。
    • 将子对象的实体键设置为“自动生成值”,并将自动同步设置为“OnInsert”。
    • 保存存储模型,然后在 Visual Studio 中清理并重建解决方案。
    • 删除任何显式设置子主键的代码。
      • LINQ 将隐式将此识别为自动递增,并检索触发器创建的 ID。
  • 在代码中,创建子对象后,将其附加到父对象,如下所示:

    ChildType newChild = new ChildType();
    DataContext.InsertOnSubmit(newChild);
    Parent.Child = newChild;
    

以下是更多资源:

干杯!

于 2010-07-31T18:57:09.830 回答
0

使用 TransactionScope 类。

请注意,如果您使用不同的数据库(或者它们位于不同的服务器上),您需要检查您的 DTC 配置。

于 2009-05-20T15:17:18.827 回答