mistahenry
mistahenry

Reputation: 8724

How to store a java object with variable number of attributes

I've looked at How to store data with dynamic number of attributes in a database, but it didn't quite answer my question. The system I am implementing is rather large, so I'll stick with the objects I am concerned about: Item and Category. An Item has a variable number of attributes depending on the Category that it belongs to. For instance, Items belonging to the "T-shirt" Category would have an attribute for size, while Items belonging to the "Car" Category would have an attribute for model. Someone logged into the system as an Admin can create new Categories with completely new attributes. What's the best way to structure this both in my Java code and in my database to make this work?

If the categories weren't dynamically created, I'd use inheritance so that I would have a TShirtItem object with its specific attributes filled in. But since it is dynamic, I'm puzzled. I saw a similar question that suggested using the Map data structure, but I am not sure how that would work...

The question I referred to at the top would suggest on the database end that I would have an Category table, and Attributes table, and relationship table linking what attributes go with what Category. This makes sense. But I'm tripped up again when thinking about the Item object. I could store the unique Category_ID in the Item table, but where would I store the attributes for each Item?

Upvotes: 3

Views: 9719

Answers (5)

Musa
Musa

Reputation: 2662

I think some attributes are major(size, color...) and some are minor(material, weight....). I will describe simplified JDL schema for this(of course exist another Stock entity which stores exact item with color, size - identified with barcode - but omitted for simpilicity). This design will help, not hard coding some part of attributes which is important for classifaing items.

Using this design Adding Data

  1. For creating data in this design => You are creating some category with it's attribute, size type(for example Shoes => 39,40,41...(options); Tshirt => S,M,L..., Iphone 7,8,X...) => inside this category particular Article - Iphone (with this way on your E-Commerce system exist Iphone)

  2. You adding specific Article Iphone X (size) - Color Black to your warehouse or stock with additional Category related Attributes => Material, Weight .... and system generates for you barcode. With this way you can easily specify Iphone with sizes and colors(without additional sql - with pure ORM) (even with additional attributes)


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}
}

Upvotes: 0

Arun
Arun

Reputation: 1

I guess you can structure ur data in such a way that u define all object types in a table and later use the below approach.

U can define tables like:

  • OBJECT_TYPE

  • OBJECTS

  • OBJ_PROPERTY_DEF

  • OBJ_PROP_VALUES

eg.
In OBJECT_TYPE Define all object types here

object_type_code(pk) obj_name

4                              car
5                              t-shirt

In OBJECTS

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  

In OBJ_PROPERTY_DEF

Define all properties corresponding to a object in this table.

Note: Using Constants file to deifine property types would avoid another table. Hopefully when you know the data types earlier.

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  

In OBJ_PROP_VALUES U can inser the values the the above specified properties

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 classed:

Define all classes with corresponding properties. eg:

  • ObjectTypeData

  • ObjectData

  • ObjectPropertyDefData

  • ObjectPropertyValuesData

In ObjectData.java

private ObjectTypeData          objType;//specifies the type
private List<ObjectPropertyValueData>   listProps; //will have all property values

//setter & getters and other req props

Upvotes: 0

Vishal
Vishal

Reputation: 3279

Instead of Java it is more of design level issue. You have to figure out the way to define DB tables and that will assist you in finding the Java objects...

Lets start from category... A category may contain lot of Items, and an Item will belong only one category(Though I practical scenarios it is not a correct assumption).

So in DATABASE you have table called Category. If you wanna define attribute based on category, then have another table called Category_attribute which will hold default value for the attribute.

Now lets move to an Item. An item belongs to a Category so Item table will have category_key to have the mapping for Item n category... Item will have its attribute which are stored in ITEM_Attribute table...

Simple form of DB objects must be somewhat as mentioned below

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

So whenever you create a Category, you will ask user to define associated attribute to the category.

At the time of creating the Item, you map it to category... And attributes associated to category should replicate with default value and map to item as well...

So you will be able to create Java objects easily...

Upvotes: 0

Gene
Gene

Reputation: 46960

If you are constrained to use an SQL database and you need to do efficient type-aware (not merely string) queries on the attributes (like list all items with category shirt having size between 4 and 8), then the structure of the database is the hard part. The Java will follow from that. If I understand correctly, you will need something like this:

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

Now for the example query:

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

Hairy multiple joins are the price to be paid for runtime-defined attrbutes.

Once you have the tables right, modeling them as Java maps is straightforward. There is redundancy in the structure above: for example the character "type" field in the attribute rows. Consider triggers to make consistency checks.

Upvotes: 3

dharam
dharam

Reputation: 8096

Here is a simple java approach to do it. While designing large systems I always suggest to look at the bigger picture. The issue here is dynamically changing attributes. It would not be easy but yeah it is interesting.

The structure of your item class has to be like the following:

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        
}

This approach suites your needs, further you can use a factory pattern to instantiate the Items depending on the category and make it an elegant code.

Please get back if you still have some doubts.

EDIT: Now there will be a complicated way to get all the attributes of an element in the code while programming, because you don't have getters or setters for the attributes. Well, the approach will help if you can maintain a Set of attributes added to the Item, in the Item class or you can query for the keySet of the item class's attributeMap property.

private Set<ItemAttibuteName> attributes;

or

attributeMap.keySet();

Happy to Help

Dharam

Upvotes: 2

Related Questions