C++ 具有大量数据的类型安全实体对象

C++ 具有大量数据的类型安全实体对象,c++,sql,entity,C++,Sql,Entity,目前,我们的系统使用类似于Java实体bean的东西,尽管它是用C++/SQL编写的。本质上,有些类(或多或少)表示表,这些类的实例相当于表行。我想补充一点,这种方法是有缺陷的,首先,请看这篇著名的文章: 另一方面,它工作得很好,只要你接受它会导致一些不纯的东西,有时会有点黑客 然而,实际问题如下:虽然这些实体中的许多在内存占用方面相对较轻(有十几列包含int、float和string),并产生了良好的性能,但其中一些实体实际上不是 有些包含二进制斑点,如网格或图片。有人可能会争辩说,这些数据一

目前,我们的系统使用类似于Java实体bean的东西,尽管它是用C++/SQL编写的。本质上,有些类(或多或少)表示表,这些类的实例相当于表行。我想补充一点,这种方法是有缺陷的,首先,请看这篇著名的文章: 另一方面,它工作得很好,只要你接受它会导致一些不纯的东西,有时会有点黑客

然而,实际问题如下:虽然这些实体中的许多在内存占用方面相对较轻(有十几列包含int、float和string),并产生了良好的性能,但其中一些实体实际上不是

  • 有些包含二进制斑点,如网格或图片。有人可能会争辩说,这些数据一开始不应该存储在数据库中,但这是另一个主题
  • 有些查询实际上并不包含大量数据(以字节为单位),但由于涉及的联接数量,获取完整的集合是一个非常大且相当缓慢的查询
  • 扭曲之处:这些“胖”对象通常在没有完整数据的情况下使用。假设您有一个“Passport”类,其中包含生物特征数据、家庭关系树,但也包含姓名和出生日期。如果要显示护照列表,只需要基本数据

    我目前正在做的是创建一个Passport实例,但分两步填充它。第一步仅添加easy字段,但保留heavy字段为空。稍后可以将实例传递给一个函数,该函数将添加所有难处理的字段。只要我不犯错误,并且在需要“完整”版本的地方使用“浅”实例,这项工作就会顺利进行。当然,我可以添加所有类型的内部检查,但这不仅不能很好地扩展(或多或少地为每个实体重新实现它们),而且非常容易出错

    因此,我的问题是:我想在编译时区分这两个版本,而不仅仅是在运行时。这样,我就能在错误发生之前抓住它们

    唯一可行的方法是将这两个部分分成两个实体部分,并将它们作为元组传递。如果第二个元组丢失,显然fat数据尚未加载。虽然这样做有效,但却会产生卑鄙的语法:

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

    我得到的所有类型安全性都是以可读性为代价的,这并不是一个很大的改进。目前,我没有更好的想法,怀疑这在C++中是不可能的,但我可能错了。非C++的建议也是受欢迎的,将来可能有更好的方法。当然,如果有人能很好地说明为什么这是不可能的,我也会接受。

    概述

    让我提出一些想法来处理“重”属性,如斑点、图像和文件。请记住,没有“一个解决方案适用于所有人”。我个人反对“装载所有重型财产”的想法,并建议其他想法

    在我继续之前,请忽略一些小的语法或逻辑错误,并将重点放在代码示例的逻辑上

    [1]定义示例

    首先,让我们从一个简单的例子开始:

    public class EmployeeClass
    {
      public:
        int     Key;
        char    FirstName[150];
        char    LastName[150];
        Image*  Photo;    // <- picture
        Blob*   Contract; // <- scanned contract
    }; // class
    
    许多开发人员只使用“commonlight构造函数”,拒绝使用多个构造函数

    [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()
    
    在前面的示例中,每个实体都是使用两个步骤创建的,“虚拟”构造函数和一个互补方法,每种情况下都不同,并带有一个有意义的标识符,在选择如何准备实体对象时非常有用

    每个物体的破坏也是如此

    [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]构造函数,而不加载“heavy”属性,一个调用它们的[fake]构造函数。或者,使用不使用它们的[fake]构造函数,显式调用特定“heavy”属性的加载程序

    如果您从文件系统路径加载映像并将其保存到数据库字段中,或者从数据库字段加载文件并将其保存到文件系统路径中,这些也会有所帮助

    干杯。

    [编辑]你的“旗帜”想法没问题

    在另一个答案中,我提供了另一个解决方案,我个人认为这是一个更好的解决方案,但是,这并不意味着你的想法是错误的

    下面的例子,我确实在某些情况下应用过,它是相同的“标志”思想,一个可能的实现,您可能想要或不想要遵循

    例如:

    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
    
    公共类EmployeeClass
    {
    //-->逻辑字段
    私人:
    沉重的布尔夫;
    //-->“实体”字段
    公众:
    int键;
    char FirstName[150];
    char LastName[150];
    图像*照片;/“重”构造器
    雇员阶级
    (
    因塔基,
    char*affirstname,
    char*ALastName,
    图片*阿佛托,
    滴状体
    )
    {
    Key=AKey;
    strcpy(FirstName,affirstname;
    strcpy(LastName,ALastName);
    照片=无眼;
    合同=合同;
    F_HeavyLoaded=真;
    }//EmployeeClass()
    
    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