2

現在、私たちのシステムは C++/SQL で書かれていますが、Java Entity Beans に似たものを使用しています。基本的に、(多かれ少なかれ) テーブルを記号化するクラスがあり、これらのクラスのインスタンスは table-row と同等です。このアプローチにはそもそも欠陥があることを付け加えたいと思います。この有名なエッセイを参照してください : http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx不純なものや、時にはハックのような結果になることを受け入れる限り、それはうまく機能します。

それにもかかわらず、実際の問題は次のとおりです。これらのエンティティの多くはメモリ フットプリントが比較的小さく (int、float、および文字列を含む多数の列)、良好なパフォーマンスが得られますが、一部のエンティティは実際にはそうではありません。

  1. 一部には、メッシュや画像などのバイナリ ブロブが含まれています。そもそもこれらを DB に格納するべきではないと主張する人もいるかもしれませんが、それは別のトピックです。
  2. 実際には多くのデータが含まれていないものもありますが (バイト単位で測定すると)、完全なセットをフェッチすると、多数の結合が関係するため、非常に大きく、かなり遅いクエリになります。

ひねり: これらの「太った」オブジェクトは、完全なデータなしで使用されることがよくあります。バイオメトリック データ、家族関係ツリーだけでなく、名前と生年月日も含む "Passport" クラスがあるとします。パスポートの一覧を表示したい場合は、基本データのみが必要です。

私が現在行っていることは、Passport インスタンスを作成することですが、2 つのステップで入力します。最初のステップでは、簡単なフィールドのみを追加しますが、重いフィールドは (NULL として) 開いたままにします。インスタンスは、後ですべての難しいフィールドを追加する関数に渡すことができます。これは、私が間違いを犯さず、「フル」バージョンが必要な「浅い」インスタンスを使用しない限り、問題なく機能します。確かに、あらゆる種類の内部チェックを追加できますが、拡張性が低いだけでなく (多かれ少なかれエンティティごとに再実装する必要があります)、非常にエラーが発生しやすくなります。

したがって、私の問題は次のとおりです。実行時だけでなく、コンパイル時に2つのバージョンを区別したいと思います。そうすれば、ほとんどのエラーが発生する前に検出できます。

機能しているように見える唯一のアイデアは、2 つの部分を 2 つのエンティティの半分に分割し、それらをタプルとして渡すことです。2 番目のタプルが欠落している場合、明らかに太いデータがまだロードされていません。それは機能しますが、卑劣な構文になります。

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

そして、私が得たすべての型安全性は読みやすさを犠牲にしており、これは大きな改善ではありません. 現在、これ以上のアイデアはなく、これは C++ では実際には不可能であると思われますが、間違っている可能性があります。C++ 以外の提案も歓迎します。将来、これを行うためのより良い方法があるかもしれません。もちろん、なぜこれが不可能なのかについて適切な指摘ができる人がいれば、それも受け入れます。

4

2 に答える 2

1

概要

ブロブ、画像、ファイルなどの「重い」プロパティを処理するためのアイデアをいくつか提案します。「すべてに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 ++開発者が気に入らないことを示唆していますが、私は個人的に、エンティティオブジェクトを処理するときに非常に役立ちます。「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()

前の例では、各エンティティは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]コンストラクターがあり、それらを呼び出す[fake]コンストラクターである「heavy」プロパティをロードしない場合があります。または、それらを使用しない[fake]コンストラクターを使用し、特定の「重い」プロパティに対してローダーを明示的に呼び出します。

これらは、ファイルシステムパスから画像をロードしてデータベースフィールドに保存する場合、またはその逆の場合に、データベースフィールドからファイルをロードしてファイルシステムパスに保存する場合にも役立ちます。

乾杯。

于 2013-02-20T16:45:51.617 に答える
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」というプライベート フラグ フィールドがあり、コンストラクタでのみ変更できます。関数を使用して、読み取り専用として公開されています。

乾杯。

于 2013-02-21T17:56:17.417 に答える