DA# Macro(6): DA# Modeler API
이번 글은 DA# Macro(매크로)에서 사용하고 있는 DA# Modeler API Object Model과 VBA 코드 구성, 소스코드 예시를 살펴본다.
5. DA# Modeler API
5.1. DA# Modeler API Object Model
이전 글(DA# Macro(1): DA#, DA# API, DA# Macro(매크로) 개요)에서 DA# API Object Model에 대해 잠깐 소개했었다.
DA# Modeler에서 제공하는 클래스 목록은 다음과 같다. (엑셀 VBE(Visual Basic Editor)에서 ‘개체 찾아보기’ 기능으로 확인하였다.)
DA# Modeler API의 Object Model은 다음과 같다. (공식 매뉴얼에는 없는 내용이고, 직접 정리하였다.)
이 중에서 가장 핵심인 Application에서 Attribute까지 Object 계층구조는 다음과 같다.
1)Application -> 2)Models -> 3)Model -> 4)Entitys -> 5)Entity -> 6)Attributes -> 7)Attribute
이 계층을 DA# Modeler 예시 모델로 표기하면 다음과 같다.
DA# Modeler API의 Object Model 계층구조와 개념, 용도를 간략하게 요약하면 다음과 같다.
5.2. 엑셀 VBA에서 DA# Modeler API 사용
DA# Modeler API를 엑셀 VBA에서 Early binding 방식으로 사용하려면 먼저 “Modeler5” library를 참조 추가해줘야 한다.
▼ 엑셀 VBE(Visual Basic Editor)로 전환(단축키 Alt + F11)하여 도구 > 참조 메뉴를 실행한다.
▼ “사용 가능한 참조” 목록에서 “Modeler5″를 체크하여 선택하고 “확인”버튼을 클릭한다.
이제 다음과 같이 VBA 코드를 작성할 수 있다.
'Modeler5 Application 개체 생성 Dim odApp As Modeler5.Application Set odApp = New Modeler5.Application '새 모델 개체 생성 Dim odModel As Modeler5.Model Set odModel = odApp.GetModelMustBe("새모델") 'Entity 생성과 값 할당 Dim odEntity As Modeler5.Entity Set odEntity = odModel.GetEntityMustBe("엔터티1") odEntity.TableName = "Table1" 'Attribute 생성과 값 할당 Dim odAttribute As Modeler5.Attribute Set odAttribute = odEntity.GetAttributeMustBe("속성1") odAttribute.ColName = "Column1"
5.3. DA# Macro VBA 코드 구성
Worksheet, UserForm, Module, Class 목록과 간략한 설명은 다음과 같다.
▼ Worksheet 개체
- shtAttributeGet: “Attribute(Get)” 시트 UI 기능 구현
- shtAttributeSet: “Attribute(Set)” 시트 UI 기능 구현
- shtEntityGet: “Entity(Get)” 시트 UI 기능 구현
- shtEntitySet: “Entity(Set)” 시트 UI 기능 구현
- shtReverse: “Reverse” 시트 UI 기능 구현
▼ 폼 개체
- frmModelFromFile: “Select Model(File)” 버튼을 클릭할 때 보여지는 사용자 폼
- frmProgress: 기능 처리 시 진행상태(ProgressBar)를 보여주기 위한 사용자 폼
▼ 모듈 개체
- modDAConstType: 기능 구현에 필요한 상수 선언, DA# Enum과 Name 변환 함수 구현
- modDAModeler: DA# 관련 기능 구현(GetModel, Reverse, SetEntity, SetAttribute 등)
- modTest: Test 코드
- modUtil: 공통기능(DoLog, ClearList, GetElapsedTime 등)
- modWinAPI: 현재 사용하지 않음
▼ 클래스 모듈 개체
- CDAAttribute: 속성 1개 단위의 클래스
- CDAAttributeList: 속성 목록을 Dictionary 구조(Key-Value)로 관리하는 클래스
- Key: ModelName:KeyName (KeyName은 엔터티명.속성명 또는 테이블명.컬럼명 형식)
- Value: CDAAttribute instance
- CDAEntity: 엔터티 1개 단위의 클래스
- CDAEntityList: 엔터티 목록을 Dictionary 구조(Key-Value)로 관리하는 클래스
- Key: ModelName:KeyName (KeyName은 엔터티명 또는 테이블명)
- Value: CDAEntity instance
- CDAFK: FK 1개 단위의 클래스
- CDAFKList: FK 목록을 Dictionary 구조(Key-Value)로 관리하는 클래스
- Key: ModelName:부모엔터티명->자식엔터티명
- Value: CDAFK instance
- CDAModel: Model 1개 단위의 클래스
- CDAModelList: Model 목록을 Dictionary 구조(Key-Value)로 관리하는 클래스
- Key: ModelName
- Value: CDAModel instance
- CDASubject: 주제영역 1개 단위의 클래스
- CDASubjectList: 주제영역 목록을 Dictionary 구조(Key-Value)로 관리하는 클래스
- Key: ModelName:SubjectName
- Value: CDASubject instance
- CUDPNameType: UDP명, 대상 여부를 관리하는 클래스 (UDP Get/Set에 사용)
5.4. DA# API 주요 클래스 활용 소스코드 예시
5.4.1. 파일로부터 모델 instance 생성
모듈 “modDAModeler”에 함수 “GetModel”로 구현하였다.
'모델명과 파일명(경로포함)으로 Model Instance 반환 Public Function GetModel(ByRef adApp As Modeler5.Application, aModelName As String, aModelFileName As String) As Modeler5.Model Dim odModel As Modeler5.Model If adApp Is Nothing Then Set adApp = New Modeler5.Application Set odModel = adApp.GetModel(aModelName) '열려 있는 모델에서 ModelName으로 비교 If (odModel Is Nothing) And (Trim(aModelFileName) <> "") Then Set odModel = GetModelAlreadyOpened(adApp, aModelName, aModelFileName) '열려 있는 모델에서 FilePath로 비교 If odModel Is Nothing Then '모델이 열려 있지 않은 경우 adApp.OpenFile (aModelFileName) Set odModel = adApp.GetActiveModel End If End If adApp.SetActiveModel odModel Set GetModel = odModel If odModel Is Nothing Then '열려 있는 모델에도 없고 파일명도 비어있는 경우 MsgBox "GetModel Error" & vbLf & _ "ModelName: " & aModelName & vbLf & _ "ModelFileName: " & aModelFileName, vbOKOnly & vbExclamation, "GetModel Error" End If End Function
GetModel 함수를 호출하기 전에 다음과 같이 Modeler5.Application instance를 먼저 생성하고 parameter로 전달한다.
Set m_odApp = New Modeler5.Application Set odModel = GetModel(m_odApp, aFileNameOnly, aFileName)
Modeler5.Application instance를 전달하지 않는 경우는 함수 내부에서 instance를 생성한다.(4행)
5.4.2. 모델 파일에서 Entity 목록 얻기
“Entity(Get)” 시트의 함수 “GetEntityListFromFile”로 구현하였다.
Public Sub GetEntityListFromFile(aFileNameOnly As String, aFileName As String, baGetYN() As Boolean, _ aUDPNameCol As Collection, aIsSaveNClose As Boolean) Dim odModel As Modeler5.Model Dim odSubjects As Modeler5.Subjects, odSubject As Modeler5.Subject Dim odLogicalPane As Modeler5.Pane, odEntitys As Modeler5.Entitys, odEntity As Modeler5.Entity Dim sModelName As String, oBaseRange As Range, oOutRange As Range, oUDPOutRange As Range Dim vOutRngArr As Variant, vUDPRngArr As Variant Set odModel = GetModel(m_odApp, aFileNameOnly, aFileName) sModelName = odModel.Name If odModel Is Nothing Then MsgBox "DA# 모델이 없습니다." & vbLf & "<모델명: " & sModelName & ">", vbCritical GoTo Finalize_Section End If odModel.ActiveAction (False) 'Undo/Redo 해제 Set oBaseRange = Range("EntityListBase").Offset(1, 0): Set oOutRange = oBaseRange.Offset(m_lRowOffset, 0) Set oUDPOutRange = Range("EntityUDPNameBase").Offset(1, 0): Set oUDPOutRange = oUDPOutRange.Offset(m_lRowOffset, 0) Set odEntitys = odModel.Entitys Dim lEntIdx As Long ReDim vOutRngArr(1 To odEntitys.Count, DA_GETENT_ItemCount) ReDim vUDPRngArr(1 To odEntitys.Count, DA_GETENT_ItemCount) For lEntIdx = 1 To odEntitys.Count Set odEntity = odEntitys.Item(lEntIdx - 1) Dim arrayEnt() As Variant arrayEnt = odEntity.Values '엔터티 Property를 Variant Array로 한번에 받아오기 vOutRngArr(lEntIdx, DA_GETENT_Sequence_IDX) = lEntIdx vOutRngArr(lEntIdx, DA_GETENT_ModelName_IDX) = sModelName vOutRngArr(lEntIdx, DA_GETENT_EntityName_IDX) = odEntity.Name '- 엔터티 Property 직접 접근 방식 ----------------------------------------------------------------------------------------------------------------------------------------- If baGetYN(DA_GETENT_EntityTableName_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityTableName_IDX) = odEntity.TableName If baGetYN(DA_GETENT_EntitySynonym_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntitySynonym_IDX) = odEntity.Synonym If baGetYN(DA_GETENT_EntityAltName_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityAltName_IDX) = odEntity.AltName If baGetYN(DA_GETENT_EntityDBOwner_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityDBOwner_IDX) = odEntity.DBOwner If baGetYN(DA_GETENT_EntityCategory_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityCategory_IDX) = GetEntityCategoryName(odEntity.Category) If baGetYN(DA_GETENT_EntityLevel_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityLevel_IDX) = odEntity.Level If baGetYN(DA_GETENT_EntityRank_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityRank_IDX) = GetEntityRankName(odEntity.Rank) If baGetYN(DA_GETENT_EntityVirtual_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityVirtual_IDX) = GetEntityTypeName(odEntity.Virtual) If baGetYN(DA_GETENT_EntityStandardType_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityStandardType_IDX) = GetStandardTypeName(odEntity.StandardType) If baGetYN(DA_GETENT_EntityStatus_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityStatus_IDX) = odEntity.Status If baGetYN(DA_GETENT_EntityPeriod_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityPeriod_IDX) = odEntity.Period If baGetYN(DA_GETENT_EntityMonthly_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityMonthly_IDX) = odEntity.Monthly If baGetYN(DA_GETENT_EntityManage_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityManage_IDX) = odEntity.Manage If baGetYN(DA_GETENT_EntityTotal_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityTotal_IDX) = odEntity.Total If baGetYN(DA_GETENT_EntityDesc_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityDesc_IDX) = Replace(odEntity.Desc, vbCrLf, vbLf) '정의 If baGetYN(DA_GETENT_EntityFlow_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityFlow_IDX) = Replace(odEntity.Flow, vbCrLf, vbLf) '데이터 처리 형태 If baGetYN(DA_GETENT_EntityRemark_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityRemark_IDX) = Replace(odEntity.Remark, vbCrLf, vbLf) '특이사항 If baGetYN(DA_GETENT_EntityNote_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityNote_IDX) = Replace(odEntity.Note, vbCrLf, vbLf) '노트 If baGetYN(DA_GETENT_EntityTag_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityTag_IDX) = odEntity.TagName '- 엔터티 Property Array 접근 방식 ----------------------------------------------------------------------------------------------------------------------------------------- ' If baGetYN(DA_GETENT_EntityTableName_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityTableName_IDX) = arrayEnt(Modeler5.ENT_TABLENAME) ' If baGetYN(DA_GETENT_EntitySynonym_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntitySynonym_IDX) = arrayEnt(Modeler5.ENT_SYNONYM) ' If baGetYN(DA_GETENT_EntityAltName_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityAltName_IDX) = arrayEnt(Modeler5.ENT_ALTNAME) ' If baGetYN(DA_GETENT_EntityDBOwner_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityDBOwner_IDX) = arrayEnt(Modeler5.ENT_DBOWNER) ' If baGetYN(DA_GETENT_EntityCategory_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityCategory_IDX) = GetEntityCategoryName(arrayEnt(Modeler5.ENT_CATEGORY)) ' If baGetYN(DA_GETENT_EntityLevel_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityLevel_IDX) = arrayEnt(Modeler5.ENT_LEVEL) ' If baGetYN(DA_GETENT_EntityRank_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityRank_IDX) = GetEntityRankName(arrayEnt(Modeler5.ENT_RANK)) ' If baGetYN(DA_GETENT_EntityVirtual_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityVirtual_IDX) = GetEntityTypeName(arrayEnt(Modeler5.ENT_VIRTUAL)) ' If baGetYN(DA_GETENT_EntityStandardType_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityStandardType_IDX) = GetStandardTypeName(arrayEnt(Modeler5.ENT_STANDARDTYPE)) ' If baGetYN(DA_GETENT_EntityStatus_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityStatus_IDX) = arrayEnt(Modeler5.ENT_STATUS) ' If baGetYN(DA_GETENT_EntityPeriod_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityPeriod_IDX) = arrayEnt(Modeler5.ENT_PERIOD) ' If baGetYN(DA_GETENT_EntityMonthly_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityMonthly_IDX) = arrayEnt(Modeler5.ENT_MONTHLY) ' If baGetYN(DA_GETENT_EntityManage_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityManage_IDX) = arrayEnt(Modeler5.ENT_MANAGE) ' If baGetYN(DA_GETENT_EntityTotal_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityTotal_IDX) = arrayEnt(Modeler5.ENT_TOTAL) ' If baGetYN(DA_GETENT_EntityDesc_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityDesc_IDX) = Replace(arrayEnt(Modeler5.ENT_DESC), vbCrLf, vbLf) '정의 ' If baGetYN(DA_GETENT_EntityFlow_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityFlow_IDX) = Replace(arrayEnt(Modeler5.ENT_FLOW), vbCrLf, vbLf) '데이터 처리 형태 ' If baGetYN(DA_GETENT_EntityRemark_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityRemark_IDX) = Replace(arrayEnt(Modeler5.ENT_REMARK), vbCrLf, vbLf) '특이사항 ' If baGetYN(DA_GETENT_EntityNote_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityNote_IDX) = Replace(arrayEnt(Modeler5.ENT_NOTE), vbCrLf, vbLf) '노트 ' If baGetYN(DA_GETENT_EntityTag_IDX) = True Then vOutRngArr(lEntIdx, DA_GETENT_EntityTag_IDX) = arrayEnt(Modeler5.ENT_TAGNAME) If Not aUDPNameCol Is Nothing Then 'Get UDP Value Dim oUDPNamePType As CUDPNameType, lUDPNameIdx As Long For lUDPNameIdx = 1 To aUDPNameCol.Count Set oUDPNamePType = aUDPNameCol(lUDPNameIdx) If oUDPNamePType.m_bUDPTargetYN = False Then GoTo SkipUDP vUDPRngArr(lEntIdx, lUDPNameIdx - 1) = odEntity.GetUDPValue(oUDPNamePType.m_sUDPName) SkipUDP: Next lUDPNameIdx End If '---------------------------------------------------------------------------------------------------- m_lRowOffset = m_lRowOffset + 1 Next lEntIdx '---------------------------------------------------------------------------------------------------- Set oOutRange = oOutRange.Resize(UBound(vOutRngArr, 1), UBound(vOutRngArr, 2)) Set oUDPOutRange = oUDPOutRange.Resize(UBound(vOutRngArr, 1), UBound(vOutRngArr, 2)) oOutRange.Value2 = vOutRngArr oUDPOutRange.Value2 = vUDPRngArr '---------------------------------------------------------------------------------------------------- Finalize_Section: odModel.ActiveAction (True) 'Undo/Redo 활성화 If aIsSaveNClose Then 'odApp.SaveActiveModelFile 'Get은 Save 하지 않도록 주석처리 m_odApp.CloseActiveModelFile End If Set odModel = Nothing Set odSubjects = Nothing Set odSubject = Nothing Set odEntity = Nothing End Sub
엔터티 Property 직접 접근 방식보다 Property Array 접근 방식이 성능이 좋으나, 이 글을 작성하는 시점에 Array로 접근할 때 값을 제대로 가져오지 못하는 현상이 있어서 직접 접근 방식으로 되돌려 두었다.
88 ~ 91행은 Variant Array를 이용하여 memory상의 2차원 배열을 엑셀 시트로 한 번에 쓴다. 이에 대한 설명은 다음 글을 참고한다.
VBA 코딩 패턴: Range Loop-쓰기(Write)
5.4.3. Entity에 값 설정하기
클래스 “CDAEntityList”의 프로시저 “SetValue”로 구현하였다.
Public Sub SetValue(aTargetModelList As CDAModelList, aIsAppendMode As Boolean, _ baSetYN() As Boolean, aIsSaveNClose As Boolean) On Error GoTo ErrHandling Dim odApp As Modeler5.Application, odModel As Modeler5.Model Dim odEntitys As Modeler5.Entitys, odEntity As Modeler5.Entity Set odApp = New Modeler5.Application Dim startTime As Date, endTime As Date, sElapedTime As String DoLog ("Entity(Set) Started...") startTime = Now frmProgress.Hide: frmProgress.InitProgress: frmProgress.Show Application.ScreenUpdating = False Dim lTargetDAModelIndex As Long, oTargetDAModel As CDAModel Dim lEntIndex As Long, sKey As String, oDAEntity As CDAEntity, lSetCount As Long, sProgressMsg As String lSetCount = 0 For lTargetDAModelIndex = 0 To aTargetModelList.Count - 1 'Model Level Loop Set oTargetDAModel = aTargetModelList.GetItemByIndex(lTargetDAModelIndex) Set odModel = GetModel(odApp, oTargetDAModel.m_s모델명, oTargetDAModel.m_s모델파일명) odModel.ActiveAction (False) 'Undo/Redo 해제 frmProgress.UpdateProgressBar aTargetModelList.Count, lTargetDAModelIndex + 1, oTargetDAModel.m_s모델명, True sProgressMsg = "[" + CStr(lTargetDAModelIndex + 1) + "/" + CStr(aTargetModelList.Count) + "] " + oTargetDAModel.m_s모델명 DoDisplayStatusMsg sProgressMsg DoLog sProgressMsg + " (" + oTargetDAModel.m_s모델파일명 + ")" If frmProgress.IsCanceled Then GoTo Finalize_Section Set odEntitys = odModel.Entitys For lEntIndex = 0 To odEntitys.Count - 1 'Entity Level Loop Set odEntity = odEntitys.Item(lEntIndex) If m_eDACompareType = DACompareLogicalName Then sKey = odModel.Name + ":" + odEntity.Name ElseIf m_eDACompareType = DAComparePysicalName Then sKey = odModel.Name + ":" + odEntity.TableName End If Set oDAEntity = GetItem(sKey) If oDAEntity Is Nothing Then GoTo Skip_Set '변경할 대상이 아니면 skip lSetCount = lSetCount + 1 'Set 개수 증가 '- 엔터티 Property 직접 접근 방식 ----------------------------------------------------------------------------------------------------------------------------------------- ' If baSetYN(DA_SETENT_EntityName_IDX) = True Then odEntity.Name = oDAEntity.m_s엔터티명 ' If baSetYN(DA_SETENT_EntityTableName_IDX) = True Then odEntity.TableName = oDAEntity.m_s테이블명 ' If baSetYN(DA_SETENT_EntitySynonym_IDX) = True Then odEntity.Synonym = oDAEntity.m_s동의어 ' If baSetYN(DA_SETENT_EntityAltName_IDX) = True Then odEntity.AltName = oDAEntity.m_s보조명 ' If baSetYN(DA_SETENT_EntityDBOwner_IDX) = True Then odEntity.DBOwner = oDAEntity.m_sDBOwner ' If baSetYN(DA_SETENT_EntityCategory_IDX) = True Then odEntity.Category = GetEntityCategoryEnum(oDAEntity.m_s분류) ' If baSetYN(DA_SETENT_EntityLevel_IDX) = True Then odEntity.Level = oDAEntity.m_sLevel ' If baSetYN(DA_SETENT_EntityRank_IDX) = True Then odEntity.Rank = GetEntityRankEnum(oDAEntity.m_s단계) ' If baSetYN(DA_SETENT_EntityVirtual_IDX) = True Then odEntity.Virtual = GetEntityTypeEnum(oDAEntity.m_s유형) ' If baSetYN(DA_SETENT_EntityStandardType_IDX) = True Then odEntity.StandardType = GetStandardTypeEnum(oDAEntity.m_s표준화) ' If baSetYN(DA_SETENT_EntityStatus_IDX) = True Then odEntity.Status = oDAEntity.m_s상태 ' If baSetYN(DA_SETENT_EntityPeriod_IDX) = True Then odEntity.Period = oDAEntity.m_s발생주기 ' If baSetYN(DA_SETENT_EntityMonthly_IDX) = True Then odEntity.Monthly = oDAEntity.m_s월간발생량 ' If baSetYN(DA_SETENT_EntityManage_IDX) = True Then odEntity.Manage = oDAEntity.m_s보존기한 ' If baSetYN(DA_SETENT_EntityTotal_IDX) = True Then odEntity.Total = oDAEntity.m_s총건수 ' If baSetYN(DA_SETENT_EntityDesc_IDX) = True Then odEntity.Desc = IIf(aIsAppendMode, odEntity.Desc + vbCrLf + oDAEntity.m_s정의, oDAEntity.m_s정의) ' If baSetYN(DA_SETENT_EntityFlow_IDX) = True Then odEntity.Flow = IIf(aIsAppendMode, odEntity.Flow + vbCrLf + oDAEntity.m_s데이터처리형태, oDAEntity.m_s데이터처리형태) ' If baSetYN(DA_SETENT_EntityRemark_IDX) = True Then odEntity.Remark = IIf(aIsAppendMode, odEntity.Remark + vbCrLf + oDAEntity.m_s특이사항, oDAEntity.m_s특이사항) ' If baSetYN(DA_SETENT_EntityNote_IDX) = True Then odEntity.Note = IIf(aIsAppendMode, odEntity.Note + vbCrLf + oDAEntity.m_sNote, oDAEntity.m_sNote) ' If baSetYN(DA_SETENT_EntityTag_IDX) = True Then odEntity.TagName = oDAEntity.m_sTag Dim arrEnt(Modeler5.ENT_ARRAYCOUNT) As Variant '- 엔터티 Property Array 접근 방식 ----------------------------------------------------------------------------------------------------------------------------------------- If baSetYN(DA_SETENT_EntityName_IDX) = True Then odEntity.Name = oDAEntity.m_s엔터티명 If baSetYN(DA_SETENT_EntityTableName_IDX) = True Then arrEnt(Modeler5.ENT_TABLENAME) = oDAEntity.m_s테이블명 If baSetYN(DA_SETENT_EntitySynonym_IDX) = True Then arrEnt(Modeler5.ENT_SYNONYM) = oDAEntity.m_s동의어 If baSetYN(DA_SETENT_EntityAltName_IDX) = True Then arrEnt(Modeler5.ENT_ALTNAME) = oDAEntity.m_s보조명 If baSetYN(DA_SETENT_EntityDBOwner_IDX) = True Then arrEnt(Modeler5.ENT_DBOWNER) = oDAEntity.m_sDBOwner If baSetYN(DA_SETENT_EntityCategory_IDX) = True Then arrEnt(Modeler5.ENT_CATEGORY) = GetEntityCategoryEnum(oDAEntity.m_s분류) If baSetYN(DA_SETENT_EntityLevel_IDX) = True Then arrEnt(Modeler5.ENT_LEVEL) = oDAEntity.m_sLevel If baSetYN(DA_SETENT_EntityRank_IDX) = True Then arrEnt(Modeler5.ENT_RANK) = GetEntityRankEnum(oDAEntity.m_s단계) If baSetYN(DA_SETENT_EntityVirtual_IDX) = True Then arrEnt(Modeler5.ENT_VIRTUAL) = GetEntityTypeEnum(oDAEntity.m_s유형) If baSetYN(DA_SETENT_EntityStandardType_IDX) = True Then arrEnt(Modeler5.ENT_STANDARDTYPE) = GetStandardTypeEnum(oDAEntity.m_s표준화) If baSetYN(DA_SETENT_EntityStatus_IDX) = True Then arrEnt(Modeler5.ENT_STATUS) = oDAEntity.m_s상태 If baSetYN(DA_SETENT_EntityPeriod_IDX) = True Then arrEnt(Modeler5.ENT_PERIOD) = oDAEntity.m_s발생주기 If baSetYN(DA_SETENT_EntityMonthly_IDX) = True Then arrEnt(Modeler5.ENT_MONTHLY) = oDAEntity.m_s월간발생량 If baSetYN(DA_SETENT_EntityManage_IDX) = True Then arrEnt(Modeler5.ENT_MANAGE) = oDAEntity.m_s보존기한 If baSetYN(DA_SETENT_EntityTotal_IDX) = True Then arrEnt(Modeler5.ENT_TOTAL) = oDAEntity.m_s총건수 If baSetYN(DA_SETENT_EntityDesc_IDX) = True Then arrEnt(Modeler5.ENT_DESC) = IIf(aIsAppendMode, odEntity.Desc + vbCrLf + oDAEntity.m_s정의, oDAEntity.m_s정의) If baSetYN(DA_SETENT_EntityFlow_IDX) = True Then arrEnt(Modeler5.ENT_FLOW) = IIf(aIsAppendMode, odEntity.Flow + vbCrLf + oDAEntity.m_s데이터처리형태, oDAEntity.m_s데이터처리형태) If baSetYN(DA_SETENT_EntityRemark_IDX) = True Then arrEnt(Modeler5.ENT_REMARK) = IIf(aIsAppendMode, odEntity.Remark + vbCrLf + oDAEntity.m_s특이사항, oDAEntity.m_s특이사항) If baSetYN(DA_SETENT_EntityNote_IDX) = True Then arrEnt(Modeler5.ENT_NOTE) = IIf(aIsAppendMode, odEntity.Note + vbCrLf + oDAEntity.m_sNote, oDAEntity.m_sNote) If baSetYN(DA_SETENT_EntityTag_IDX) = True Then arrEnt(Modeler5.ENT_TAGNAME) = oDAEntity.m_sTag odEntity.Values = arrEnt '-------------------- Set UDP Value -------------------- If oDAEntity.m_oUDPDic.Count = 0 Then GoTo Skip_Set 'UDP Collection이 비어 있으면 Skip Dim vUDPName As Variant, sUDPValue As String For Each vUDPName In oDAEntity.m_oUDPDic.Keys 'Dictionary에는 Set대상 UDP만 가지고 있음 sUDPValue = oDAEntity.m_oUDPDic(vUDPName) odEntity.SetUDPValue vUDPName, sUDPValue Next vUDPName Skip_Set: odEntity.UpdateDrawEntity Next lEntIndex odModel.ActiveAction (True) 'Undo/Redo 활성화 If aIsSaveNClose Then odApp.SaveActiveModelFile odApp.CloseActiveModelFile End If Next lTargetDAModelIndex frmProgress.UpdateProgressBar aTargetModelList.Count, lTargetDAModelIndex + 1, oTargetDAModel.m_s모델명, True ErrHandling: Resume Next Finalize_Section: Application.ScreenUpdating = True endTime = Now sElapedTime = GetElapsedTime(startTime, endTime) DoLog ("Entity(Set) Finished. [ElapsedTime: " + sElapedTime + "]") frmProgress.SetDoneMsg sProgressMsg, sElapedTime MsgBox "처리완료" + vbCrLf + _ "처리건수: " + CStr(lSetCount) + vbCrLf + _ "Elapsed Time: " + sElapedTime, vbInformation End Sub
- 21행: Undo/Redo를 해제한다. (메모리 절약과 성능 향상 목적)
- 10, 25, 112행: DoLog 함수로 처리 상태를 기록한다. (이 함수는 Windows API ‘OutputDebugMessage’를 이용하는 사용자 함수이고, 이와 관련하여 별도로 포스팅할 예정이다)
- 83행: 엔터티 Property가 담긴 Array(Variant type)를 Entity.Values에 할당하여 한번에 값을 설정한다.
여기까지 DA# Macro에서 사용하고 있는 DA# Modeler API Object Model과 VBA 코드 구성, 소스코드 예시를 살펴보았다.
소스코드는 3년여에 걸쳐 시간 날 때 가끔씩 코딩과 리팩토링을 반복하다 보니, 전체적인 코드 일관성은 썩 좋지 않다. 전반적인 리팩토링은 언젠가 손대긴 해야 하는데, 언제일지는 모르겠다.
DA#을 사용하는 데이터 모델러, DA(Data Architect, 데이터 아키텍트)에게 이 도구가 도움이 되길 바란다.
<< 관련 글 목록 >>
- DA# Macro(1): DA#, DA# API, DA# Macro (매크로) 개요
- DA# Macro(2): DA# Macro(매크로) 기능(1)-공통기능, Entity Get/Set
- DA# Macro(3): DA# Macro(매크로) 기능(2)-Attribute Get/Set
- DA# Macro(4): DA# Macro(매크로) 기능(3)-Reverse
- DA# Macro(5): 사용상 주의사항/참고사항, 다운로드, 향후 추가 예정 기능, 일러두기
- DA# Macro(6): DA# Modeler API
- DA# Macro 기능 시연 영상 (YouTube)
- DA# Macro 설명글 목차 , 다운로드