0

私が取り組んでいる関連テクノロジーは次のとおりです。

  • DevartのドットコネクトforOracle(Linq-to-Sql for Oracleを容易にするため)。
  • 強く型付けされたADO.NETデータセット。
  • Oracleデータベース。

課題は次のとおりです。

  • 私のレガシーコードは、ADO.NETデータセットとテーブルアダプターを使用してデータベースの更新を送信します。
  • そのコードをLinq-to-Sqlに変換し始めたいのですが、コードのチャーンとリスクを最小限に抑えるために少しずつ変換したいと思います。

これが私の概念実証スキーマです。

親テーブル

  • Parent.Id
  • 親の名前

子テーブル

  • Child.Id
  • Child.ParentId
  • Child.Name

これが私の概念実証コードブロックです:

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データセットテーブルアダプターを使用して、子テーブルの更新をコミットしたいと思います。

ここに2つの興味深い脚注があります:

  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

Oracleのトランザクションについては何も知りません...しかし、ドットネット側では、トランザクションを自分で制御するのは問題ないはずです。両方のテクノロジーが同じ接続インスタンスを使用していることを確認してください。

ORMではなく接続を介してトランザクションを制御する場合は、トランザクションスコープを使用します:http://msdn.microsoft.com/en-us/library/ms172152.aspx

于 2009-05-20T14:51:08.507 に答える
1

同じ問題が発生し、次の 2 つのエラーが発生しました。

  • 整合性制約違反 (ORA-02291)
  • 「キーがデータベースで生成されていない場合、同じキーを持つエンティティを挿入できません」

問題は、子オブジェクトの ID 列が正しく設定されていなかったことです。DotConnect LINQ が ID キーを想定していない場合、オブジェクトのプロパティはアドホックに設定されているように見え、更新が不連続になり、整合性違反につながります。

修正は次のとおりです。

  • 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 に答える