단일 트랜잭션에 LINQ-to-SQL 변경 및 ADO.NET 데이터 세트 테이블 어댑터 업데이트를 포함시킬 수 있습니까?

StackOverflow https://stackoverflow.com/questions/888299

문제

내가 함께 일하는 관련 기술은 다음과 같습니다.

  • Oracle에 대한 Devart의 DOT Connect (Oracle의 Linq-to-SQL을 용이하게하기 위해).
  • 강력하게 입력 한 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 데이터 세트로 Child Table에 업데이트를 커밋하고 싶습니다. 테이블 어댑터.

다음은 두 가지 흥미로운 각주입니다.

  1. 이 모든 것들 공장 반대로. 즉, 데이터 어댑터와 함께 부모 테이블에 변경 사항을 제출하고 LINQ-to-SQL을 사용하여 하위 테이블을 변경하려면 ... 작동 할 것이다.
  2. 트랜잭션을 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을 통한 연결을 통해 트랜잭션을 제어하면 트랜잭션 범위를 사용합니다. http://msdn.microsoft.com/en-us/library/ms172152.aspx

다른 팁

이 두 가지 오류가 발생하여 같은 문제가있었습니다.

  • 무결성 제약 위반 (ORA-02291)
  • "키가 생성되지 않은 경우 동일한 키로 엔티티를 삽입 할 수 없습니다."

문제는 Child Object의 신원 열이 제대로 설정되지 않았다는 것입니다. DotConnect LINQ가 ID 키를 가정하지 않으면 객체 속성이 임시로 설정된 것으로 보이며 비 순위행 업데이트가 발생하여 무결성 위반으로 이어집니다.

다음은 수정 사항입니다.

  • LINQ는 아동의 기본 키가 엔티티 키이며 자동 생성임을 알아야합니다.
  • Oracle에서는 Child Object의 자동 증가 키를 설정하십시오.
  • 먼저 시퀀스를 만듭니다.

      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 파일)을 엽니 다.
    • Child Object의 엔티티 키를 '자동 생성 값'으로 설정하고 'OnInsert'로 자동 동기화됩니다.
    • 스토리지 모델을 저장하고 Visual Studio에서 솔루션을 청소하고 재건하십시오.
    • 자녀의 기본 키를 명시 적으로 설정하는 코드를 제거하십시오.
      • LINQ는 이것을 자동으로 인식하여 인식하고 트리거 제작 ID를 검색합니다.
  • 코드에서, 자식 객체를 만든 후 다음과 같이 부모에게 첨부하십시오.

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

추가 리소스는 다음과 같습니다.

건배!

TransactionScope 클래스를 사용하십시오.

다른 데이터베이스를 사용하는 경우 (또는 별도의 서버에 상주하는 경우) DTC 구성을 확인해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top