2013-02-20 16 views
2

目前,我們的系統使用類似於Java Entity Beans的東西,雖然它是用C++/SQL編寫的。從本質上講,有(或多或少)符號化表的類,這些類的實例等同於錶行。我想補充一點,這種方法是有缺陷的,看看這篇着名的文章:http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx 另一方面,它運作良好,只要你認爲它會導致一些不純的東西和一些黑客攻擊倍。然而,實際問題如下:雖然這些實體中的很多實體在內存佔用(包含整數,浮點數和字符串的十幾個列)中的亮度相對較低,並且性能很好,但其中一些實際上並不是這樣。類型安全的數據較重的實體對象

  1. 一些包含二進制斑點,如網格或圖片。有人可能會爭辯說,這些不應該存儲在數據庫中開始,但這是另一個話題。
  2. 有些實際上並不包含大量數據(以字節爲單位),但是由於涉及的連接數量多,提取整個集合是一個非常大而且非常慢的查詢。

扭曲:這些「胖」對象通常在沒有完整數據的情況下使用。想象一下,你有一個「護照」班,其中包含生物識別數據,家庭關係樹,還有姓名和出生日期。如果您想顯示護照列表,您只需要基本數據。

我現在正在做的是創建一個Passport實例,但分兩步填充它。第一步只添加簡單字段,但將重量字段保留爲空(如NULL)。該實例稍後可以傳遞給一個將添加所有困難字段的函數。這可以毫無障礙地工作,只要我不犯錯,並在需要「完整」版本的情況下使用「淺」實例。當然,我可以添加各種內部檢查,但不僅可以縮小比例(爲每個實體或多或少地重新實現它們),它也非常容易出錯。

我的問題是這樣的:我想在編譯時區分這兩個版本,而不僅僅是在運行時。那樣,我會在他們發生之前捕捉到大多數錯誤。

似乎工作的唯一想法是將兩部分拆分爲兩個實體 - 一半,並將它們作爲元組傳遞。如果第二個元組丟失,顯然胖數據尚未加載。雖然這樣的作品,它導致卑鄙的語法:

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

和所有類型安全我得到的是在可讀性的成本,這是不是一個很大的改進。目前,我沒有更好的想法,並且懷疑這在C++中實際上是不可能的,但我可能是錯的。非C++ - 建議也是受歡迎的,未來可能有更好的方法來做到這一點。當然,如果有人能說出爲什麼這是不可能的,那麼我也會接受。

回答

1

概述

讓我提出一些想法來處理像斑點,圖像,文件「重」的屬性。請記住,沒有「一個解決方案」。我個人拒絕了「加載所有重財產」標誌的想法,&建議替代想法。

之前,我繼續,請忽略小的語法或邏輯錯誤,並專注於代碼示例的邏輯。

[1]定義實例

首先,讓我們從一個簡單的例子:

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

首先,你不必加載或不加載,「重」屬性,因爲「實體」模型或其他編程技術這樣說。

事實上,我不會爲重物添加標誌,因爲這意味着加載所有「重」屬性或根本不加載任何「重」屬性。而且,有時你可能不得不加載其中的一些,但不是全部。

[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++開發人員不喜歡的建議,但是,我個人發現在處理實體對象時非常有用。我使用「兩步初始化」。

對於每個實體類,我聲明瞭一個構造函數,它沒有參數用於清除字段 和添加具有非常特定標識符的虛擬方法,該函數接受構造函數的作用。

然後,我可以添加幾個虛擬方法作爲構造函數,比如決定是否加載「重」屬性。

所以,在前面的例子成爲這樣的事情:

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() 

在前面的例子中,使用2個步驟,該「虛擬」構造創建的每個實體,和互補方法中,每種情況下不同,具有有意義的標識符,在選擇如何準備實體對象時很有用。

對於每個對象的銷燬也是如此。

[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() 

額外的方法,你可能有一個[虛假]構造忽略他們,不加載「重」的屬性,一個[虛假]構造函數調用它們。或者,使用不使用它們的[fake]構造函數,&顯式調用加載器以獲得特定的「重」屬性。

這些也有助於從文件系統路徑加載圖像,&將它們保存到數據庫字段或反之亦然從數據庫字段加載文件&將它們保存到文件系統路徑。

乾杯。

+0

謝謝您的深入解釋。這與我們目前正在做的非常接近,並且運行得很好。然而,它在處理大量內容方面不是類型安全的。 – 2013-02-21 09:44:16

+0

@Kajetan Abt:我的建議。旨在(「思考不同」),以另一種方式處理屬性,從開始就知道它需要這些屬性,而不是在之後檢測,如果它們在哪裏加載。祝你好運。 – umlcat 2013-02-21 17:47:07

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

再一次,這個工作,但它並沒有解決我的問題,我想檢查*編譯時間*實體是否加載或不。 – 2013-02-24 22:41:01

相關問題