Kori 3월 12일, 2022에 포스트됨 공유하기 3월 12일, 2022에 포스트됨 Docwiki에 있는 "Caching Updates (FireDAC)"를 번역한 글 (번역일: 2022년 3월 12일) 위로 가기: Editing Data (FireDAC) 목차 일반 사항 (Generalities) 중앙집중식 캐시된 업데이트 (Centralized Cached Updates) 업데이트를 추적하기 (Tracking Updates) 업데이트를 반영하기 (Applying Updates) 에러를 검토하기 (Reviewing Errors) 기타 자료 (See Also) 예제 (Samples) 일반 사항 (Generalities) 캐시된 업데이트 모드에서는 Post / Delete 메소드를 호출하지 않고, 업데이트를 데이터베이스로 포스트(Post)하기를 뒤로 미룬다. 그 결과, 업데이트 여러개를 하나의 묶음으로 포스트(Post)할 수 있고, 원한다면 트랜젝션 하나에 묶어서 보낼 수도 있다. 데이터셋을 캐시된 업데이트 모드로 지정하려면, CachedUpdates 프로퍼티를 True로 지정한다. 그러면 해당 데이터셋은 이 프로퍼티가 마지막으로 True가 된 시점 이후, 또는 마지막으로 CancelUpdates / CommitUpdates 가 호출된 이후에 발생한 모든 변경을 추적한다. 변경 내역은 변경 일지에 포함되며, 여기에는 모든 변경이 발생 시점 순서로 남아있다. FireDAC은 동일 레코드의 여러 버전을 추적하지 않는다. 가장 마지막 변경은 이전 내용을 덮어쓰고, 이전 내용은 업데이트 순서 상 가장 뒤로 옮겨진다. FireDAC은 "분산형"과 "중앙 집중식" 캐시된 업데이트 모드를 지원한다. 분산형 캐시된 업데이트 모드--각 데이터셋 별로 독립적으로 변경을 추적한다. 고전적 방식이며, 기본 모드이다. 중앙 집중식 캐시된 업데이트 모드--여러 데이터셋들이 변경 로그 하나를 공유하고 변경 내역은 발생 순서대로 기록된다. 중앙집중식 캐시된 업데이트 (Centralized Cached Updates) 애플리케이션에서 여러 데이터셋에서 발생된 변경을 발생 순서대로 기록하고 적용하려면 중앙집중식 캐시된 업데이트를 사용한다. 이 목적을 이루려면, TFDSchemaAdapter 인스턴스 하나가 해당 데이터셋들 모두의 SchemaAdapter 프로퍼티에 할당되어야 한다. TFDSchemaAdapter는 여러 데이터셋 안에 있는 모든 로우(Row)와 변경을 담는 중앙 저장소 역할을 한다. 무엇보다, 중앙집중식 캐시된 업데이트는 마스터-디테일 관계에서 유용하다. 마스터 데이터셋의 변경을 디테일 데이터셋으로 전파하기 때문이다. 여기에는 자동-증가 필드 값도 포함된다. 디테일 데이터셋으로 전파하기를 켜러면 FetchOptions.DetailCascade를 반드시 True로 지정한다. 그러면 다음과 같이 작동한다. 마스터-디테일 변경을 동기화, 그 결과 마스터와 디테일 데이터셋의 변경은 발생 순서 대로 기록되고 적용된다. 예를 들어: 마스터 레코드가 먼저 삽입(Insert)되고 나서 해당 디테일 레코드가 삽입(Insert)된다; 마스터 Identity 컬럼 값을 디테일 데이터셋에 전파한다. 예를 들어, 디테일 데이터셋이 마스터 데이터셋의 Identity 컬럼에 연결되어 있는 레코드에 대해 당신이 업데이트를 반영하면 해당 디테일 레코드는 반드시 마스터 Identity 컬럼의 실제 값을 받아야 한다; 마스터 레코드가 삭제될 때 해당 디테일 레코드도 연쇄적으로 삭제된다. 예를 들어, 마스터 레코드가 삭제되면 해당 디테일 레코드 모두가 삭제되고 변경 로그에 기록된다; 마스터 필드의 변경을 디테일 데이터셋에게 전파한다. 전파되려면 다음 조건이 충족되어야 한다: 데이터셋이 마스터-디테일 관계이어야 한다; 범위 기반 M/D가 사용되어야 한다; 마스터 데이터셋이 FireDAC 데이터셋(TFDQuery, TFDStoredProc, TFDMemTable)이어야 한다. 디테일 데이터셋이 라이브 데이터 창 모드에서 TFDTable이 아니어야 한다. DetailServerCascade를 사용하면, FireDAC이 클라이언트 측 연쇄(cascading) 변경을 데이터베이스에 적용할 것인지 말 것인지를 조절할 수 있다. DetailServerCascadee는 FetchOptions.DetailCascade과 함께 사용한다. 중앙집중식 캐시된 업데이트와 전파하기를 켜려면 다음 단계를 진행한다 (먼저, 범위 기반 M/D를 설정하고 CachedUpdates 프로퍼티를 True로 지정한다): TFDSchemaAdapter를 폼 위에 올려 놓는다. 마스터 데이터셋의 SchemaAdapter 프로퍼티를 위의 TFDSchemaAdapter로 지정한다. 디테일 데이터셋의 SchemaAdapter 프로퍼티를 위와 동일한 TFDSchemaAdapter로 지정한다. 디테일 데이터셋의 FetchOptions.DetailCascade를 True로 지정한다. 위와 같이 하면, 인-메모리 참조 제약이 디테일 데이터셋에 적용된다. 이것은 아래의 SQL 명령과도 유사하다 ALTER TABLE <디테일> ADD CONSTRAINT FOREIGN KEY (<디테일 필드(들)>) REFERENCES <master> (<마스터 필드(들)>) ON DELETE CASCADE ON UPDATE CASCADE 업데이트를 반영하려면, 애플리케이션에서 데이터셋의 ApplyUpdates 메소드 대신, TFDSchemaAdapter.ApplyUpdates 메소드를 사용해야 한다. 에러를 교정(Reconcile)하려면, 데이터셋의 Reconcile 대신, TFDSchemaAdapter.Reconcile 메소드를 사용한다. 보다 자세한 내용은 중앙집중식 캐시된 업데이트 예제를 본다. 업데이트를 추적하기 (Tracking Updates) 애플리케이션이 중앙집중식 캐시된 업데이트 모드에서 작동하고 있으면, 당신은 변경을 추적하고 원한다면 각 데이터셋의 변경을 되돌릴 수도 있다. 변경을 추적하려면 아래에 있는 프로퍼티를 사용한다. UpdatesPending - 변경 로그가 비어있지 않으면 True를 반환; ChangeCount - 업데이트의 총 갯수를 반환; UpdateStatus - 현재 레코드의 변경 유형을 반환; FilterChanges - 변경 유형으로 레코드 걸러내기 기존 변경을 되돌리려면 아래의 프로퍼티와 메소드를 사용한다. SavePoint – 현재 변경 로그 상태를 설정/획득 한다; RevertRecord – 현재 레코드를 이전 (원래) 상태로 되돌린다; UndoLastChange – 마지막에 변경된 레코드로 가서 그것을 이전 (원래) 상태로 되돌린다; CancelUpdates – 변경 로그 안에 있는 모든 레코드를 되돌린다. 예를 들어, 간단하게 Undo 기능을 구현하려면, actUndo 라는 액션을 하나 만들고 그 액션에 다음과 같이 이벤트 핸들러를 달아준다. procedure TForm1.actUndoUpdate(Sender: TObject); begin actUndo.Enabled := FDQuery1.UpdatesPending; end; procedure TForm1.actUndoExecute(Sender: TObject); begin FDQuery1.UndoLastChange(True); end; 다른 예로, 인-메모리 트랜젝션을 구현하여 업데이트 묶음 되돌리기를 구현하려면, 다음과 같이 한다. FDQuery1.CachedUpdates := True; iSavePoint := FDQuery1.SavePoint; try FDQuery1.Append; ... FDQuery1.Post; FDQuery1.Append; ... FDQuery1.Post; FDQuery1.Append; ... FDQuery1.Post; except FDQuery.SavePoint := iSavePoint; end; 주의: 캐시된 업데이트 모드에서는, 다음과 같은 메소드와 프로퍼티가 변경 일지를 사용하여 작동한다. Data 프로퍼티에는 모든 레코드가 들어있다. 심지어 삭제된 것과 업데이트된 사항까지 모두 들어있다.; Delta 프로퍼티는 변경 일지에 담긴 삭제, 삽입, 업데이트된 레코드를 반환한다; CopyRecord, CopyDataSet 메소드는 새 업데이트를 생성하지만 변경 일지는 복사하지 않는다; LoadFromStream, LoadFromFile, SaveToStream, SaveToFile은 데이터를 변경 일지와 함께 불러오거나 저장한다. 캐시된 업데이트 모드에서, 변경 일지에 변경이 남아있을 경우, 일부 메소드와 프로퍼티 설정은 예외를 발생시킨다. 업데이트 사항은 반드시 커밋(Commit) 되거나 취소(Cancel)되어야 한다. 다음과 같은 경우가 여기에 해당된다. Refresh; CachedUpdates를 False로 지정 업데이트를 반영하기 (Applying Updates) 데이터베이스에 업데이트를 반영하려면, ApplyUpdates 메소드를 사용한다. 만약 업데이트 반영 중인 레코드에서 예외(exception)가 발생되면, 이 예외(exception)는 해당 레코드에 연결된다. ApplyUpdates 메소드에 대해 다음 사항을 알아두자. 예외를 일으키지 않고, 발생된 예외의 갯수를 반환한다; 업데이트들을 묶어서 트랜젝션 하나로 반영하지 않는다. 애플리케이션에서 직접 해야 한다; 즉시 업데이트와 동일한 업데이트 포스트(Post) 로직을 사용한다. 업데이트를 반영한 후에도, 변경된 레코드들은 여전히 변경 로그 안에 남아있다. 변경 로그에서 제거하고, 이 레코드들을 변경되지 않음으로 표시하려면, CommitUpdates 메소드를 호출한다. 예를 들어, FDQuery1.CachedUpdates := True; FDQuery1.Append; ... FDQuery1.Post; FDQuery1.Append; ... FDQuery1.Post; FDQuery1.Append; ... FDQuery1.Post; FDConnection1.StartTransaction; iErrors := FDQuery1.ApplyUpdates; if iErrors = 0 then begin FDQuery1.CommitUpdates; FDConnection1.Commit; end else FDConnection1.Rollback; 주의: 이 경우는 AutoCommitUpdates가 False로 지정된 경우에 해당된다. 만약 AutoCommitUpdates가 True로 지정되면, CommitUpdates를 명시적으로 호출하지 않아도 된다. True로 지정되면, ApplyUpdates를 호출하여 진행된 업데이트에서 성공한 레코드들은 모두 자동으로 변경없음으로 표시되기 때문이다. 에러를 검토하기 (Reviewing Errors) ApplyUpdates 호출 안에서 에러가 발생하면, ApplyUpdates는 해당 에러를 내부 데이터 레코드 구조 안에 기록하고, AMaxErrors 숫자에 도달하기 전까지 업데이트 처리를 지속한다. ApplyUpdates는 예외를 일으키지 않는다. ApplyUpdates 진행 후, 에러가 발생된 레코드를 모두 교정하려면, 교정 처리(reconciling process) 또는 에러가 발생한 레코드 걸러내기를 한다. 레코드를 교정(reconcile)하려면, OnReconcileError 이벤트 핸들러를 할당하고 Reconcile 메소드를 호출한다. OnReconcileError 이벤트 핸들러는 에러를 분석하고 현재 레코드 필드 값을 읽고 변경한다. 빠져나갈 때에는, 액션을 할당하여 FireDAC 코드가 에러와 함께 현재 레코드에 수행할 작업을 지정해야 한다. Reconcile 메소드를 호출한 후에는 ApplyUpdates를 다시 호출하여 에러가 있는 레코드의 변경을 다시 포스트(Post)할 수 있다. 에러가 있는 레코드만 걸러내려면, FilterChanges에 rtHasErrors를 포함한다. 그후 걸러진 데이터셋을 탐색하고 RowError 프로퍼티를 읽어서 현재 레코드에 연결된 Exception 오브젝트를 얻는다. 예를 들어 var oErr: EFDException; ... if FDQuery1.ApplyUpdates > 0 then begin FDQuery1.FilterChanges := [rtModified, rtInserted, rtDeleted, rtHasErrors]; try FDQuery1.First; while not FDQuery1.Eof do begin oErr := FDQuery1.RowError; if oErr <> nil then begin // exception 오브젝트 처리 ... end; FDQuery1.Next; end; finally FDQuery1.FilterChanges := [rtUnmodified, rtModified, rtInserted]; end; end; 기타 자료 (See Also) Update Command Generation Overriding Posting Updates 예제 (Samples) FireDAC Schema Adapter 예제 FireDAC TFDMemTable Cached Updates 예제 FireDAC TFDQuery Centralized Cached Updates 예제 인용하기 이 댓글 링크 다른 사이트에 공유하기 더 많은 공유 선택 사항
Recommended Posts
이 토의에 참여하세요
지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.