2013-02-20 2 views
2

현재 C++/SQL로 작성되었지만 시스템에서 Java Entity Beans와 비슷한 것을 사용합니다. 본질적으로 테이블을 상징하는 클래스가 존재하며 클래스의 인스턴스는 테이블 행과 같습니다. 나는이 접근법이 처음부터 잘못되었다고 덧붙이고 싶다.이 유명한 에세이를 보자. http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx 반면에 그것은 불순한 점과 약간의 해킹을 초래할 것이라는 점을 인정하는 한 잘 작동한다. 타임스.무거운 데이터가있는 유형 안전 엔터티 개체

그럼에도 불구하고 실제 문제는 다음과 같습니다. 이러한 엔티티 중 많은 수가 메모리 풋 프린트 (int, float 및 문자열을 포함하는 12 개의 열)가 상대적으로 가볍지 만 좋은 성능을 나타내지 만 그 중 일부는 실제로 그렇지 않습니다.

  1. 일부는 메쉬 또는 그림과 같은 이진 모양을 포함합니다. 하나는 DB에 저장해서는 안되며 다른 주제라고 주장 할 수 있습니다.
  2. 일부는 실제로 많은 양의 데이터 (바이트 단위로 측정)를 포함하지 않지만 전체 세트를 가져 오는 것은 관련된 조인의 수 때문에 매우 크고 느린 쿼리입니다.

트위스트 : 이러한 "뚱뚱한"개체는 종종 전체 데이터없이 사용됩니다. 생물 측정 데이터, 가족 관계 나무뿐만 아니라 이름과 생년월일도 포함하는 "Passport"클래스가 있다고 가정 해보십시오. 여권 목록을 표시하려면 기본 데이터 만 있으면됩니다.

현재 수행중인 작업은 Passport 인스턴스를 만드는 것이지만 두 단계로 채우는 것입니다. 첫 번째 단계에서는 쉬운 필드 만 추가하지만 무거운 필드는 열어 둡니다 (NULL로). 인스턴스는 나중에 모든 어려운 필드를 추가하는 함수로 전달 될 수 있습니다. 내가 실수를하지 않고 "전체"버전이 필요한 "얕은"인스턴스를 사용하는 한, 이것은 장애없이 작동합니다. 물론 모든 종류의 내부 검사를 추가 할 수는 있지만 그 규모가 제대로 작동하지 않을뿐만 아니라 오류가 발생하기 쉽습니다.

내 문제는 다음과 같습니다. 런타임시에만 컴파일 타임에서 두 버전을 구별하고 싶습니다. 그런 식으로, 나는 그들이 일어날 전에 대부분의 오류를 잡을 것이다.

작동하는 것처럼 보이는 유일한 아이디어는 두 부분을 두 개의 엔티티 반으로 나눠서 튜플로 전달하는 것입니다. 두 번째 튜플이 누락 된 경우에는 뚱뚱한 데이터가 아직로드되지 않은 것입니다. 그 작동하지만, 그것은 비겁한 구문 결과 :

std::vector< EntityTuple<EmptyPassport, FullPassport>> 

내가 얻을 수있는 모든 유형의 안전은 중대한 개선되지 가독성의 비용이다. 현재, 나는 더 좋은 아이디어를 가지고 있지 않으며, 이것이 C++에서 실제로 불가능하다고 생각합니다. 그러나 나는 잘못 될 수 있습니다. Non-C++ - 제안도 환영합니다. 향후 더 나은 방법이있을 수 있습니다. 물론, 이것이 불가능한 이유에 대해 누구나 좋은 지적을 할 수 있다면, 나는 또한 그것을 받아 들일 것입니다.

답변

1

개요

나 모양, 이미지 파일과 같은 "헤비"속성을 처리하기 위해 몇 가지 아이디어를 제안하자. 모든 사람들을위한 하나의 해결책이 없다는 것을 기억하십시오. 저는 개인적으로 "모든 무거운 물건을 적재하십시오"깃발이라는 아이디어를 거부합니다. &은 대안 아이디어를 제안합니다.

계속하기 전에 작은 구문 또는 논리 오류를 무시하고 코드 예제의 논리에 집중하십시오.

[1] 예를 정의

먼저, 간단한 예제로 시작하자 : 당신은로드 할 수없는 모든의

public class EmployeeClass 
{ 
    public: 
    int  Key; 
    char FirstName[150]; 
    char LastName[150]; 
    Image* Photo; // <- picture 
    Blob* Contract; // <- scanned contract 
}; // class 

첫 번째 또는로드하지 마십시오 "무거운" "Entity"모델 또는 다른 프로그래밍 기술이 그렇게 말하기 때문에

실제로 무거운 물체에 플래그를 추가하지 않습니다. 이는 모든 "무거운"속성을로드하거나 "무거운"속성을 전혀로드하지 않기 때문입니다. 그리고 때로는 그 중 일부를로드해야 할 수도 있지만 모두가로드되지는 않습니다.

[2] 하중 특성 보통

, 프로그램의 논리 특성을로드 할 때 나타낸다.

일반적인 방법은 각각의 경우에 대해 다른 생성자 사용하기 위해 :

public class EmployeeClass 
{ 
    public: 
    int  Key; 
    char FirstName[150]; 
    char LastName[150]; 
    Image* Photo; 
    Blob* Contract; 

    public: 
    // --> generic constructor 
    EmployeeClass() 
    { 
     Key = 0; 
     strcpy(FirstName, ""); 
     strcpy(LastName, ""); 
     Photo = null; 
     Contract = null; 
    } // EmployeeClass() 

    // --> "light" constructor 
    EmployeeClass 
    (
     int AKey, 
     char* AFirstName, 
     char* ALastName 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName; 
     strcpy(LastName, ALastName); 
     Photo = null; 
     Contract = null; 
    } // EmployeeClass() 

    // --> "heavy" constructor 
    EmployeeClass 
    (
     int AKey, 
     char* AFirstName, 
     char* ALastName, 
     Image* APhoto, 
     Blob* AContract 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName; 
     strcpy(LastName, ALastName); 
     Photo = APhoto; 
     Contract = AContract; 
    } // EmployeeClass() 

    void Insert(); 
}; // class 

void Test() 
{ 
    ... 
    int AKey = 0; 
    char AFirstName[150]; 
    char ALastName[150]; 
    Image* APhoto = null; 
    Blob* AContract = null; 

    // --> calling "light" constructor 

    AKey = 1; 
    strcpy(AFirstName, "Mary"); 
    strcpy(ALastName, "Thompson"); 

    EmployeeClass* AEmployee = new EmployeeClass 
     (AKey, AFirstName, ALastName); 

    AEmployee->Insert(); 

    // --> calling "heavy" constructor 

    AKey = 2; 
    strcpy(AFirstName, "John"); 
    strcpy(ALastName, "Doe"); 

    Image* APhoto = LoadPhoto(); 
    Blob* AContract = LoadContract(); 

    EmployeeClass* AEmployee = new EmployeeClass 
     (AKey, AFirstName, ALastName, APhoto, AContract); 

    AEmployee->Insert(); 

    // --> calling "dummy" constructor, 
    // --> more work, but, more flexible 

    AKey = 1; 
    strcpy(AFirstName, "Mary"); 
    strcpy(ALastName, "Thompson"); 

    EmployeeClass* AEmployee = new EmployeeClass(); 
    AEmployee->Key = AKey; 
    strcpy(AEmployee->FirstName, AFirstName); 
    strcpy(AEmployee->LastName, ALastName); 
    AEmployee->Photo = LoadPhoto(); 
    AEmployee->Contract = LoadContract(); 
    AEmployee->Insert(); 

    ... 
} // void Test() 

많은 개발자 만 "일반적인 빛 생성자"를 사용을 & 여러 생성자를 가지고있는 생각을 거부한다.

[3] 추가 도움말

잠시은 "무거운"속성은 나중에 계속,의는 생략하자.

이것은 많은 C/C++ 개발자들이 싫어하지만, 개인적으로 엔티티 개체를 다룰 때 매우 유용하다고 생각합니다. "2 단계 초기화"를 사용합니다.

각 엔티티 클래스에 대해 필드를 지우는 매개 변수가없는 생성자를 선언하고 및 생성자 역할을하는 매우 구체적인 식별자가있는 가상 메서드를 추가합니다.

그런 다음 "무거운"속성을로드하는 wheter를 결정하는 것과 같이 생성자로 작동하는 몇 가지 가상 메서드를 추가 할 수 있습니다. 각각의 경우에 대해 서로 다른 각 엔티티는 2 단계의 "더미"생성자를 사용하여 생성 된 이전 예에서

public class EmployeeClass 
{ 
    public: 
    bool F_EmployeeClass_IsReady; 
    public: 
    int  Key; 
    char FirstName[150]; 
    char LastName[150]; 
    Image* Photo; 
    Blob* Contract; 

    public: 
    // --> only generic constructor 
    Employee() 
    { 
     F_EmployeeClass_IsReady = false; 

     Key = 0; 
     strcpy(FirstName, ""); 
     strcpy(LastName, ""); 
     Photo = null; 
     Contract = null; 
    } // EmployeeClass() 

    virtual bool IsReady() 
    { 
     return F_EmployeeClass_IsReady; 
    } // bool IsReady(...) 

    // --> works like "generic" constructor from previous example 
    virtual void Create() 
    { 
     Key = 0; 
     strcpy(FirstName, ""); 
     strcpy(LastName, ""); 
     Photo = null; 
     Contract = null; 

     F_EmployeeClass_IsReady = true; 
    } // void Create() 

    // --> works like "light" constructor from previous example 
    virtual void CreateLight 
     (
     int AKey, 
     char* AFirstName, 
     char* ALastName 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName); 
     strcpy(LastName, ALastName); 
     Photo = null; 
     Contract = null; 

     F_EmployeeClass_IsReady = true; 
    } // void CreateLight() 

    virtual void Destroy() 
    { 
     F_EmployeeClass_IsReady = false; 
    } // void Destroy() 

    // --> works like "heavy" constructor from previous example 
    virtual void CreateHeavy 
     (
     int AKey, 
     char* AFirstName, 
     char* ALastName, 
     Image* APhoto, 
     Blob* AContract 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName); 
     strcpy(LastName, ALastName); 
     Photo = APhoto; 
     Contract = AContract; 

     F_EmployeeClass_IsReady = true; 
    } // void CreateHeavy() 

    void Insert(); 
}; // class 

void Test() 
{ 
    ... 
    int AKey = 0; 
    char AFirstName[150]; 
    char ALastName[150]; 
    Image* APhoto = null; 
    Blob* AContract = null; 

    // --> calling "light" constructor 

    AKey = 1; 
    strcpy(AFirstName, "Mary"); 
    strcpy(ALastName, "Thompson"); 

    EmployeeClass* AEmployee = new EmployeeClass(); 
    AEmployee->CreateLight(AKey, AFirstName, ALastName); 

    AEmployee->Insert(); 

    AEmployee->Destroy(); 
    delete AEmployee; 

    // --> calling "heavy" constructor 

    AKey = 2; 
    strcpy(AFirstName, "John"); 
    strcpy(ALastName, "Doe"); 

    Image* APhoto = LoadPhoto(); 
    Blob* AContract = LoadContract(); 

    EmployeeClass* AEmployee = new EmployeeClass(); 
    AEmployee->CreateHeavy 
    (AKey, AFirstName, ALastName, APhoto, AContract); 

    AEmployee->Insert(); 

    AEmployee->Destroy(); 
    delete AEmployee; 

    // --> calling "dummy" constructor, 
    // --> more work, but, more flexible 

    AKey = 1; 
    strcpy(AFirstName, "Mary"); 
    strcpy(ALastName, "Thompson"); 

    EmployeeClass* AEmployee = new EmployeeClass(); 
    AEmployee->Create(); 

    AEmployee->Key = AKey; 
    strcpy(AEmployee->FirstName, AFirstName); 
    strcpy(AEmployee->LastName, ALastName); 
    AEmployee->Photo = LoadPhoto(); 
    AEmployee->Contract = LoadContract(); 

    AEmployee->Insert(); 

    AEmployee->Destroy(); 
    delete AEmployee; 

    ... 
} // void Test() 

및 상보있어서,

그래서, 위의 예는 다음과 같이 될 의미있는 식별자로, 엔티티 객체를 준비하는 방법을 선택할 때 유용합니다.

같은 것은 각 개체의 파괴입니다.

[4] 헤비 등록 방법

마지막으로, 당신이 필요할 때 "무거운"속성을로드 담당하는 몇 가지 방법을 추가 할 수 있습니다. 때로는 명시 적으로 호출되고 경우에 따라 자동으로 호출됩니다. 추가 방법으로

public class EmployeeClass 
{ 
    public: 
    bool F_EmployeeClass_IsReady; 
    public: 
    int  Key; 
    char FirstName[150]; 
    char LastName[150]; 
    Image* Photo; 
    Blob* Contract; 

    public: 
    // --> only generic constructor 
    Employee() 
    { 
     F_EmployeeClass_IsReady = false; 

     Key = 0; 
     strcpy(FirstName, ""); 
     strcpy(LastName, ""); 
     Photo = null; 
     Contract = null; 
    } // EmployeeClass() 

    virtual bool IsReady() 
    { 
     return F_EmployeeClass_IsReady; 
    } // bool IsReady(...) 

    void LoadPhoto(); 
    void SavePhoto(); 

    void LoadContract(); 
    void SaveContract(); 

    // --> works like "generic" constructor from previous example 
    virtual void Create() 
    { 
     Key = 0; 
     strcpy(FirstName, ""); 
     strcpy(LastName, ""); 
     Photo = null; 
     Contract = null; 

     F_EmployeeClass_IsReady = true; 
    } // void Create() 

    // --> works like "light" constructor from previous example 
    virtual void CreateLight 
     (
     int AKey, 
     char* AFirstName, 
     char* ALastName 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName); 
     strcpy(LastName, ALastName); 
     Photo = null; 
     Contract = null; 

     F_EmployeeClass_IsReady = true; 
    } // void CreateLight() 

    virtual void Destroy() 
    { 
     F_EmployeeClass_IsReady = false; 
    } // void Destroy() 

    // --> works like "heavy" constructor from previous example 
    virtual void CreateHeavy 
     (
     int AKey, 
     char* AFirstName, 
     char* ALastName, 
     Image* APhoto, 
     Blob* AContract 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName); 
     strcpy(LastName, ALastName); 
     Photo = APhoto; 
     Contract = AContract; 

     F_EmployeeClass_IsReady = true; 
    } // void CreateHeavy() 


    // --> works like "heavy" constructor from previous example 
    virtual void CreateAndLoad 
     (
     int AKey, 
     char* AFirstName, 
     char* ALastName 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName); 
     strcpy(LastName, ALastName); 

     LoadPhoto(); 
     LoadContract; 

     F_EmployeeClass_IsReady = true; 
    } // void CreateAndLoad() 

    void Insert(); 
}; // class 

void Test() 
{ 
    ... 
    int AKey = 0; 
    char AFirstName[150]; 
    char ALastName[150]; 
    Image* APhoto = null; 
    Blob* AContract = null; 

    // --> calling "load" constructor 

    AKey = 1; 
    strcpy(AFirstName, "Mary"); 
    strcpy(ALastName, "Thompson"); 

    EmployeeClass* AEmployee = new EmployeeClass(); 
    AEmployee->CreateLoad(AKey, AFirstName, ALastName); 

    AEmployee->Insert(); 

    AEmployee->Destroy(); 
    delete AEmployee; 

    ... 
} // void Test() 

, 당신은 그들을 무시 A [가짜] 생성자가 수 있으며, "무거운"속성을 부르는 [가짜] 생성자를로드하지 않습니다.또는 그들을 사용하지 않는 [가짜] 생성자를 사용하면 & 명시 적으로 특정 "무거운"속성에 대한 로더를 호출합니다.

파일 시스템 경로에서 이미지를로드하는 경우 &을 데이터베이스 필드 또는 viceversa에 저장하고 데이터베이스 필드에서 파일을로드하는 경우 & 파일 시스템 경로에 저장하십시오.

건배.

+0

깊이있는 설명에 감사드립니다. 이것은 우리가 현재하고있는 일에 매우 가깝고 잘 작동합니다. 그러나 무거운 내용을 처리하는 방법은 유형에 안전하지 않습니다. –

+0

@Kajetan Abt : 내 생각. ("다르게 생각하다"), 다른 방법으로 속성을 처리하기 시작했다. 시작부터 알려진대로 속성을 요구하고 이후에 검색하지 않는다. 행운을 빕니다. – umlcat

1

[편집] 당신의 "깃발"생각은 괜찮습니다.

다른 해결책으로 저는 개인적으로 더 나은 해결책을 생각하지만 아이디어가 잘못되었음을 의미하지는 않습니다.

다음 예는 일부 경우에 적용했지만 동일한 '플래그'아이디어, 구현 가능성, 따라하고 싶거나 원하지 않을 수 있습니다.

예이 예에서

public class EmployeeClass 
{ 
    // --> logic fields 
    private: 
    bool F_HeavyLoaded; 

    // --> "entity" fields 
    public: 
    int  Key; 
    char FirstName[150]; 
    char LastName[150]; 
    Image* Photo; // <- picture 
    Blob* Contract; // <- scanned contract 

    public: 
    // --> constructors 

    EmployeeClass 
    (
     int AKey, 
     char* AFirstName, 
     char* ALastName 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName; 
     strcpy(LastName, ALastName); 
     Photo = null; 
     Contract = null; 

     F_HeavyLoaded = false; 
    } // EmployeeClass() 

    // --> "heavy" constructor 
    EmployeeClass 
    (
     int AKey, 
     char* AFirstName, 
     char* ALastName, 
     Image* APhoto, 
     Blob* AContract 
    ) 
    { 
     Key = AKey; 
     strcpy(FirstName, AFirstName; 
     strcpy(LastName, ALastName); 
     Photo = APhoto; 
     Contract = AContract; 

     F_HeavyLoaded = true; 
    } // EmployeeClass() 

    public: 
    // --> "entity" methods 


    bool IsHeavyLoaded() { return F_HeavyLoaded; } 

    void Insert(); 
    void Update(); 
    void Delete(); 
}; // class 

, 그것은 스트 만 변경 될 수있다 "F_IsHeavyLoaded"라는 전용 플래그 필드가있다. 함수를 사용하여 공개적으로 읽기 전용으로 사용할 수 있습니다.

건배.

+0

다시 말하지만,이 기능은 작동하지만 엔티티가로드되었는지 여부를 * 컴파일 할 때 확인하고 싶은 문제점을 해결하지 못합니다. –