【问题标题】:How to store a java object with variable number of attributes如何存储具有可变数量属性的java对象
【发布时间】:2012-11-20 05:10:56
【问题描述】:

我查看了How to store data with dynamic number of attributes in a database,但它并没有完全回答我的问题。我正在实现的系统相当大,所以我会坚持我关心的对象:项目和类别。一个项目具有可变数量的属性,具体取决于它所属的类别。例如,属于“T-shirt”类别的项目将具有大小属性​​,而属于“汽车”类别的项目将具有模型属性。以管理员身份登录系统的人可以创建具有全新属性的新类别。在我的 Java 代码和数据库中构建它以使其工作的最佳方法是什么?

如果类别不是动态创建的,我会使用继承,这样我就有一个填充了特定属性的 TShirtItem 对象。但由于它是动态的,我很困惑。我看到了一个类似的问题,建议使用 Map 数据结构,但我不确定它是如何工作的......

我在顶部提到的问题会在数据库端建议我将有一个类别表、属性表和关系表,这些表将哪些属性与哪些类别相关联。这是有道理的。但是在考虑 Item 对象时,我又被绊倒了。我可以将唯一的 Category_ID 存储在 Item 表中,但是我将在哪里存储每个 Item 的属性?

【问题讨论】:

    标签: java database


    【解决方案1】:

    如果您受限于使用 SQL 数据库,并且您需要对属性执行有效的类型感知(不仅仅是字符串)查询(例如列出所有衬衫类别尺寸在 4 到 8 之间的项目),那么结构数据库是最难的部分。 Java 将随之而来。如果我理解正确,您将需要这样的东西:

    categories:
      id : integer (pk)
      name : varchar
    
    attributes:
      id : integer (pk)
      of_category : integer (fk -> categories.id)
      name : varchar
      type : char(1) // 'N' for number, 'S' for string, etc.
    
    items:
      id : integer (pk)
      of_category : integer (fk -> categories.id)
    
    number_values:
      value : number
      of_item : integer (pk, fk -> items.id)
      of_attribute : integer (pk, fk -> attributes.id)
    
    string_values:
      value : varchar
      of_item : integer (pk, fk -> items.id)
      of_attribute : integer (pk, fk -> attributes.id)
    
    ... additional table for each attribute type
    

    现在是示例查询:

    select * from categories c, items i, attributes a, number_values v
    where c.name = 'shirt' and
          a.of_category = c.id and
          a.name = 'size' and
          a.id = v.of_attribute and
          i.id = v.of_item and
          v.value between 4 and 8
    

    毛茸茸的多重连接是为运行时定义的属性付出的代价。

    一旦您拥有正确的表格,将它们建模为 Java 地图就很简单了。上述结构中存在冗余:例如属性行中的字符“类型”字段。考虑使用触发器进行一致性检查。

    【讨论】:

    • 谢谢!我选择 dharam's 作为正确答案只是因为他先提交了它。我希望我能同时选择这两个,因为我问了一个两部分的问题,而你的答案是正确的。您能否详细说明“考虑使用触发器进行一致性检查”的含义?
    • 啊,好吧。花了几分钟才算出数据库表的正常形式。我很高兴能提供帮助。触发器是一种 SQL 功能,它允许在发生 INSERT、UPDATE 和 DELETE 操作(以及其他一些情况)时运行代码。您可以在此代码中进行一致性检查。例如,您可以检查数字表中的值是否实际引用了类型字段为“N”的属性。一切都以数据完整性为名。触发代码通常在存储过程中实现。 Google 会为您指明方向。
    【解决方案2】:

    这是一个简单的java方法来做到这一点。在设计大型系统时,我总是建议着眼于更大的图景。这里的问题是动态改变属性。这并不容易,但很有趣。

    您的项目类的结构必须如下所示:

    class Item{
       private String itemName; // I assume all items will have a name.
       private Map<ItemAttibuteName , Object> attributeMap ; // this will be a dynamic map.
    
       public Map<ItemAttibuteName, Object> getAttributeMap(){//getter for attribute map
           if( null == attributeMap)
              return new HashMap<String, Object>(); 
           return attributeMap ;
    
       }
       // you can synchronize this if needed
       public void setAttribute(ItemAttibuteName name, Object value){ 
           attributeMap.put(name, value);
       }
    
       public Object getAttribute(ItemAttibuteName name){ 
           return attributeMap.get(name);
       }
    }
    
    public enum ItemAttibuteName{
        SIZE,
        COLOUR        
    }
    

    这种方法可以满足您的需求,此外,您还可以使用工厂模式根据类别实例化项目并使其成为优雅的代码。

    如果您仍有疑问,请回复。

    编辑: 现在将有一种复杂的方法来在编程时获取代码中元素的所有属性,因为您没有属性的 getter 或 setter。好吧,如果您可以在 Item 类中维护添加到 Item 的一组属性,或者您可以查询 item 类的 attributeMap 属性的 keySet,则该方法将有所帮助。

    private Set<ItemAttibuteName> attributes;
    

    attributeMap.keySet();
    

    乐于助人

    达兰

    【讨论】:

    • 超级有帮助!感谢 Gene 在下面的回答,我将拥有一个 Attribute 对象。每个类别都有一个私有迭代器,其中包含与其对应的所有属性对象。在实例化代理 Item 对象时,我将创建一个 hashmap 并使用 Attribute 名称作为键,并将其值作为值。我将有一个 getAttribute(String) 方法,它使用提供的字符串值(属性名称)来获取特定属性的值。还有一个 setAttribute(String,Value)。我认为这会奏效!
    • 是的,太棒了!您可以通过对所有可能的属性名称使用枚举来进一步简化它:)
    【解决方案3】:

    它更多的是设计级别的问题,而不是 Java。您必须弄清楚定义数据库表的方法,这将有助于您找到 Java 对象...

    让我们从类别开始......一个类别可能包含很多项目,一个项目将只属于一个类别(虽然我在实际场景中这不是一个正确的假设)。

    所以在 DATABASE 中有一个名为 Category 的表。如果你想根据类别定义属性,那么有另一个名为 Category_attribute 的表将保存属性的默认值。

    现在让我们移动到一个项目。一个项目属于一个类别,因此项目表将具有 category_key 以具有项目 n 类别的映射...项目将具有其存储在 ITEM_Attribute 表中的属性...

    DB对象的简单形式一定有点像下面提到的

    Category
    C_Id
    Name
    
    
    Category_Attribute
    CA_ID
    Name
    Default_value
    Category_Id(FK)
    
    
    Item
    I_ID
    Name
    C_ID(FK)
    
    
    Item_attribute
    IA_ID
    Ca_ID(FK from category_attribute table)
    I_ID(FK from item table)
    Value
    

    因此,每当您创建一个类别时,您都会要求用户为该类别定义相关属性。

    在创建项目时,您将其映射到类别...并且与类别关联的属性应该使用默认值复制并映射到项目...

    因此您将能够轻松创建 Java 对象...

    【讨论】:

      【解决方案4】:

      我想你可以用这样的方式来构造你的数据,你可以在一个表中定义所有的对象类型 然后使用下面的方法。

      你可以定义如下表:

      • OBJECT_TYPE

      • 对象

      • OBJ_PROPERTY_DEF

      • OBJ_PROP_VALUES

      例如。
      在 OBJECT_TYPE 在此处定义所有对象类型

      object_type_code(pk) obj_name

      4                              car
      5                              t-shirt
      

      在对象中

      obj_code(pk) object_type_code(fk) obj_name


      1           4       BMW  
      2           4       Maruti  
      3           4       Honda  
      
      4           5       levis  
      5           5       polo  
      6           5       reebock  
      

      在 OBJ_PROPERTY_DEF 中

      定义与该表中的对象对应的所有属性。

      注意:使用常量文件定义属性类型将避免另一个表。 希望当您更早了解数据类型时。

      obj_prop_code(pk) obj_code(fk) property_type property_name

      ------------- -------- ------------- -------------

      12          6       8 (Integer)     size  
      13          6       9 (String)      color  
      14          6       10 (float)      weight  
      15          6       11 (Boolean)        is_coloured  
      16          6       9 (String)      comments  
      
      17          3       9 (String)      model  
      18          3       8 (Integer)     version  
      19          3       9 (String)      color  
      20          3       9 (String)      comments  
      

      在 OBJ_PROP_VALUES 中 你可以在上面指定的属性中插入值

      obj_prop_val_code(pk) obj_prop_code(fk) obj_prop_value(VARCHAR) prop_value_sufix

      ------ ------------- -------------- --- --------------

      101             12          30              -  
      102             13          green           -  
      103             14          126            gms  
      104             15          0               -
      105             16          looks cool      -  
      
      106             17          c532            -  
      107             18          3.22            -  
      108             19          black           -  
      109             20          awesome car     -   
      

      Reg Java 分类:

      定义所有具有相应属性的类。 例如:

      • ObjectTypeData

      • 对象数据

      • ObjectPropertyDefData

      • ObjectPropertyValuesData

      在 ObjectData.java 中

      private ObjectTypeData          objType;//specifies the type
      private List<ObjectPropertyValueData>   listProps; //will have all property values
      
      //setter & getters and other req props
      

      【讨论】:

        【解决方案5】:

        我认为有些属性是主要的(尺寸、颜色...)而有些是次要的(材料、重量...)。我将为此描述简化的JDL 模式(当然存在另一个 Stock 实体,它存储具有颜色、大小的精确项目 - 用条形码标识 - 但为简单起见省略)。这种设计将有所帮助,而不是硬编码对物品分类很重要的属性的某些部分。

        使用此设计添加数据

        1. 用于在此设计中创建数据 => 您正在创建一些具有其属性、尺寸类型的类别(例如鞋子 => 39,40,41...(选项);Tshirt => S,M, L..., Iphone 7,8,X...) => 在此类别中的特定文章 - Iphone(您的电子商务系统上存在这种方式的 Iphone)

        2. 您将特定的 Iphone X(尺寸)物品添加到您的仓库或库存中,并带有额外的类别相关属性 => 材料、重量 .... 和系统为您生成的条形码。通过这种方式,您可以轻松地为 Iphone 指定尺寸和颜色(无需额外的 sql - 使用纯 ORM)(即使有额外的属性)

        
        enum CategoryTarget{
            F, M, K
        }
        
        entity Category{
            name String,
            imageUrl String,
            showHomepage Boolean,
            target CategoryTarget,
            accOrder Integer,
            isLastNode Boolean
        }
        
        entity Article{
            status Integer,
            name String,
            code String,
            rating Double,
            imageUrl String,
            isPopular Boolean
        }
        
        relationship ManyToOne{
            Category{parent} to Category,
            Article{category} to Category{article},
            Category{sizeType} to SizeType
        }
        
        relationship ManyToMany{
            Category{attribute} to Attribute{category}
        }
        
        entity Attribute{
            name String
        }
        
        entity AttributeOption{
            name String
        }
        
        relationship OneToMany{
            Attribute{attributeOption} to AttributeOption{attribute}
        }
        
        entity SizeType{
            name String
        }
        
        entity ArticleSize{
            name String,
            accOrder Integer
        }
        
        relationship OneToMany{
            SizeType{articleSize} to ArticleSize{sizeType}
        }
        
        relationship ManyToMany{
            Article{attributeOption} to AttributeOption{article}
        }
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-05
          • 1970-01-01
          • 1970-01-01
          • 2013-07-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多