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에서 제공하는 클래스 목록
DA# Modeler에서 제공하는 클래스 목록

DA# Modeler API의 Object Model은 다음과 같다. (공식 매뉴얼에는 없는 내용이고, 직접 정리하였다.)

DA# API Object Model
DA# API Object Model

이 중에서 가장 핵심인 Application에서 Attribute까지 Object 계층구조는 다음과 같다.

1)Application -> 2)Models -> 3)Model -> 4)Entitys -> 5)Entity -> 6)Attributes -> 7)Attribute

이 계층을 DA# Modeler 예시 모델로 표기하면 다음과 같다.

DA# 모델러 API 핵심 Object
DA# 모델러 API 핵심 Object

DA# Modeler API의 Object Model 계층구조와 개념, 용도를 간략하게 요약하면 다음과 같다.

DA# Modeler API Object Model 계층 구조
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″를 체크하여 선택하고 “확인”버튼을 클릭한다.

Modeler5 참조 추가
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 목록과 간략한 설명은 다음과 같다.

DA# Macro VBA 코드 구성
DA# Macro VBA 코드 구성

▼ 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, 데이터 아키텍트)에게 이 도구가 도움이 되길 바란다.


<< 관련 글 목록 >>

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

ko_KR한국어