DA(Data Architecture) 도구/DA# Macro 도구

DA# Macro(6): DA# Modeler API

ProDA 2021. 8. 19.

이 글은 새로운 블로그로 옮겼습니다. 5초후 자동으로 이동합니다.

▶ 새로운 블로그 주소: https://prodskill.com/

▶ 새로운 글 주소: https://prodskill.com/da-macro-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# Macro(1): DA#, DA# API, DA# Macro(매크로) 개요

    이번 글은 국산 데이터 모델링 도구인 DA#을 소개하고 DA# v5부터 제공되는 API와 이를 활용하여 개발한 도구인 DA# Macro(매크로)에 대해 살펴본다. 목차 1. DA# Macro(매크로) 개요 1.1. 데이터 모델링 도

    prodtool.tistory.com

     

    DA# Modeler에서 제공하는 클래스 목록은 다음과 같다. (엑셀 VBE(Visual Basic Editor)에서 '개체 찾아보기' 기능으로 확인하였다.)

    DA# Modeler에서 제공하는 클래스 목록
    DA# Modeler에서 제공하는 클래스 목록

     

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

    DA# Modeler 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)

     

    VBA 코딩 패턴: Range Loop-쓰기(Write)

    목차 요약 Variant Array를 이용하여 엑셀 시트에서 많은 데이터를 쓸때 성능을 개선하는 코딩 패턴에 대해 소개한다. 엑셀 시트에서 많은 데이터를 읽을 때 성능을 개선하는 방법은 아래 글에서 이

    prodtool.tistory.com

     

     

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

     

    댓글

    💲 추천 글