Linq to sql 能否在单个事务中包含linq到sql的更改和ADO.NET数据集表适配器更新?

Linq to sql 能否在单个事务中包含linq到sql的更改和ADO.NET数据集表适配器更新?,linq-to-sql,ado.net,transactions,dataset,devart,Linq To Sql,Ado.net,Transactions,Dataset,Devart,以下是我正在使用的相关技术: Devart的用于Oracle的dot Connect(促进用于Oracle的Linq到Sql) 强类型ADO.NET数据集 甲骨文数据库 以下是挑战: 我的旧代码使用ADO.NET数据集和表适配器提交数据库更新 我希望开始将代码转换为Linq到Sql,但我希望零碎地将代码转换和风险降至最低 以下是我的概念证明模式: 父表 父.Id 父项名称 子表 儿童身份证 Child.ParentId 孩子的名字 以下是我的概念验证代码块: using Sys

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

  • Devart的用于Oracle的dot Connect(促进用于Oracle的Linq到Sql)
  • 强类型ADO.NET数据集
  • 甲骨文数据库
以下是挑战:

  • 我的旧代码使用ADO.NET数据集和表适配器提交数据库更新
  • 我希望开始将代码转换为Linq到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到Sql的提交更改方法
    • 我想做出一个承诺 使用 ADO.NET数据集表适配器

以下是两个有趣的脚注:

  • 这一切在我看来都是可行的 相反。也就是说,如果我想 将更改提交到父表 使用数据适配器并更改为 具有linq到sql的子表。。。 那就行了
  • 我试图显式地将事务附加到dataadapter,但编译器不允许,因为它是一种不同类型的事务

                    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();
    

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


    当我们通过连接而不是ORM控制事务时,我们使用事务作用域:

    使用TransactionScope类


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

    我遇到了相同的问题,遇到以下两个错误:

    • 完整性约束冲突(ORA-02291)
    • “如果密钥不是数据库生成的,则无法插入具有相同密钥的实体”
    问题是子对象的标识列设置不正确。如果DotConnect LINQ不采用标识键,则对象属性似乎是临时设置的,导致非连续更新,从而导致完整性冲突

    以下是修复方法:

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

    • 接下来创建OnInsert触发器:

    • 修改存储模型以合并新的自动生成主键:

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

    以下是进一步的资源:

    • 插入主键递增的行
    • 用级联序列保存实体上下文的问题
    • 自动增量列支持(LinqConnect+Oracle)
    干杯

      DROP SEQUENCE MyChild_SEQ;
      CREATE SEQUENCE MyChild_SEQ
          MINVALUE 1
          MAXVALUE 999999999999999999999999999
          START WITH 1
          INCREMENT BY 1
          CACHE 20;
    
    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
    
    ChildType newChild = new ChildType();
    DataContext.InsertOnSubmit(newChild);
    Parent.Child = newChild;