Asset Management Database Design - mysql

I am currently busy implementing a basic Asset Management System. It will not be very complicated. Simply something to keep track of any asset with it's name, serial number, parts number and type etc. The problem I have however, is that I want to incorporate books as well. Unfortunately, books have a very different structure than normal assets (for example title, authors, isbn codes etc.).
I would like some insight from the community as to what design they think is best. Incorporate books in asset management (and if so, how should the database design look), or should I simply write a completely seperate, independant Library module (maybe with some functionality to export a book to the Asset Management System [with fewer / other fields]).
Thanks!
EDIT: Something else that is possible is to make the capture screen dynamic, so the user can specify the fields and the values. This can then be stored in as XML in the database. But his would not be my preferred way of doing it.
EDIT 2: I forgot to mention, I am very bound by the technologies that I may use. These are MySQL, GWT, Hibernate and Spring (no Spring transactions).

One approach could be to use a document style no-sql database (such as Mongo) to store the assets. That way each different type of asset can easily have its own set of fields without requiring additional tables, etc.
Basically what I'm picturing is pseudo-code similar to:
class Asset
{
int AssetNumber;
int AssetType;
string Description;
// etc.
}
class BookAsset : Asset
{
// book-specific fields
}
class ElectronicsAsset : Asset
{
// electronics-specific fields
}
// etc.
So additional asset types can just be additional derived classes. Then each asset would be written to the document database as its own distinct document, and retrieved by its asset number (or searched for based on the fields it contains, etc.) or name or however it's stored.
This would give you a quick and easy system with the flexibility you'll likely want as you track additional assets, or additional information about existing assets.
Edit based on your edit: User-defined fields should work just fine with this. You can set it up as some kind of key/value dictionary on the object, or even just add the fields to the object itself if using a more dynamic language. The "base asset" would be composed of the fields which are absolutely required, the rest can be more loosely-defined, conditionally required, user-specified, etc.

It makes sense to separate the general notion of an asset from the specifics of each type of asset you want to be able to incorporate. Typically, this would take the form of a master Asset table, with different tables for each distinct type of asset you wish to include, i.e. Book, Hardware, Furniture. The structure might look like this:
Asset(AssetId, Description, Comments)
HardwareAsset(HardwareAssetId, AssetId, SerialNumber, ...)
BookAsset(BookAssetId, AssetId, ISBN, Publisher, Author, ...)
Where AssetId in both HardwareAsset and BookAsset is a foreign key to the Asset table. That way, you can keep track of different assets and group them together when it should matter.
EDIT: Alternatively, you can create a key - value table to store values for individual objects, which could look like this:
AssetValue(AssetValueId, AssetId, Key, Value)
However, this is a cumbersome solution that, while still providing for searchable fields, will quickly bloat your database. To mitigate the problem you can limit the field size depending on your requirements. I do not suggest serializing the dictionary inside a single field, as this will bloat your database even more.

From the technology constraints I would suggest keeping the modules separate.

Yes on the main table you can flag what type of asset it is. So if it
is a book asset them a foreign key can link it to the book items. this
way you will not waste space on those assets that do not have these items.

Related

Extending a Table with Users' Individual Preferred Custom Properties

What is the most performance-efficient way to allow end-users to add custom properties to a core table used by an application.
For example, core table FRIENDS has columns ID, FIRST_NAME, LAST_NAME, and BIRTHDAY.
User 1 wants to also track additional properties FAVORITE_COLOR and LUCKY_NUMBER, but User 2 wants to also track different additional properties ZODIAC_SIGN, MARRIAGE_ANNIVERSRY_DATE, and GOLF_HANDICAP.
I have implemented two approaches for testing:
First approach: Add a new table FRIENDS_CUSTOM_PROPERTIES having an FK pointer back to FRIENDS and two columns for value pairs (KEY and VALUE such as FAVORITE_COLOR, YELLOW). This approach potentially requires many queries on FRIENDS_CUSTOM_PROPERTIES to retrieve all the properties for a given friend.
Second approach: Add extension columns right on the FRIENDS table itself of varying data types for CUSTOM_1, CUSTOM_2, ... CUSTOM_64, etc. If a user needed more custom properties than there were columns, my design would "spill over" to approach 1. This approach is more brute force but easily results in many NULL column values on many rows.
I can make both work but am unsure the best approach to determine which is better (or if there is already a clear best practice one way or another).
Thanks.
Approach number one is called entity-attribute-value as Rick James noted in the comments. It can do the job, but you sacrifice lots of useful features of SQL, like data types and constraints. See EAV FAIL for some of my writing on this.
You wrote something about running "many queries" but there's no advantage to doing that. You should plan on fetching the set of custom properties for a user in one query, and saving it to a map object in your client application.
The latter approach number two is incomplete. You would also need to store some kind of metadata so you know that for user 1, CUSTOM_1 means "Favorite Color" and CUSTOM_2 means "Lucky Number" and so on. Where do you plan to store the meaning of each column per user?
At least with the EAV design, each attribute comes with a key, so you know exactly what it means. And EAV allows for an unlimited number of properties, because each property gets a new row.
Ultimately, any design that allow for "user-defined properties" conflicts with principles of relational databases. Your columns no longer have any concept of a type. Read a book like SQL and Relation Theory to understand more about this.

How to design a "dynamic" relational database

We're building a new piece of software for our company, where we want to manage our inventory.
The goal for the tool is to be customizable by the customer.
My part is mostly on the DB side. We have chosen MariaDB as our DB engine, and while we are working with the rather static functionality of a relational DB, we want to realize a rather dynamic solution.
Our chief programmer has explained to me the basics of the concept I shall implement into our DB:
We want a table which basically just consists of other tables.
Lets call it "maintable".
Maintable shall then reference its "attributes", which are the other tables.
For example, maintable references "Workstations".
"Workstations" then contains attributes like CPU, RAM, Drives, PSU etc..
And now comes the part which I didn't completely understand. The actual VALUES to these attributes in "Workstations" shall not be inserted into "Workstations". Instead, they are packed into another (junction?) table.
The reason for this approach is that the customer shall be able to customize the DB to his needs.
When the customer wants to add another attribute, he shall be able to do so. For example, if a new PSU now requires another attribute for an additional serial number, then the customer shall be able to simply create this new attribute in the front-end input form and then persist it to the DB.
If someone could point to good tutorials explaining this type of DB concept, then I would be glad as well! :=)

Is this an reasonable use case for storing JSON in MySQL?

I understand that it is generally considered a "bad idea" to store JSON in a MySQL column due to the fact that it becomes difficult to maintain and is not easily searched, or otherwise queried. However, I feel that the scenario I have encountered in my application is a reasonable use case for storing JSON data in my MySQL table. I am indeed looking for an answer, particularly one that may point out any difficulties which I may have overlooked, or if there is any good reason to avoid what I have planned and if so, an alternate approach.
The application at hand provides resource and inventory management, and supports building Assemblies, which may contain an infinite number of sub assemblies.
I have a table which holds all of the metadata for items, such as their name, sku, retail price, dimensions, and most importantly to this question: the item type. An item can either be a part or an assembly. For items defined as assemblies, their contents are stored in another table, item_assembly_contents whose structure is rather expected, using a parent_id column to link the children to the parent. As you may expect, at any time, a user may decide to add or remove an item from an assembly, or otherwise modify the assembly contents or delete it entirely.
Here is a visual representation of the above table description, populated with data that when composed, creates an assembly containing another assembly.
With the above structure, any item that is deleted from the items table will also be automatically deleted in the item_assembly_contents table via InnoDB ON DELETE CASCADE.
Here is a very simple example Assembly in JSON format, demonstrating a single Sub Assembly structure.
{
"id":1,
"name":"Fruit Basket",
"type":"assembly",
"contents":[
{
"id":10,
"parent_id":1,
"name":"Apple",
"type":"part",
"quantity":1
},
{
"id":11,
"parent_id":1,
"name":"Orange",
"type":"part",
"quantity":1
},
{
"id":12,
"parent_id":1,
"name":"Bag-o-Grapes",
"type":"assembly",
"quantity":1,
"contents":[
{
"id":100,
"parent_id":12,
"name":"Green Grape",
"quanity":10,
"type":"part"
},
{
"id":101,
"parent_id":12,
"name":"Purple Grape",
"quanity":10,
"type":"part"
}
]
}
]
}
The Fruit Basket is an Assembly, which contains a Sub-Assembly named "Bag o Grapes". This all works wonderfully, until orders and shipments come into consideration.
Take for example, an outbound shipment containing an assembly. At any time, the user must be able to see the contents of the assembly, as they were defined at the time of shipment, which rules out simply retrieving the data from the items and item_assembly_contents table, as these tables may have been modified since the shipment was created. Therefore, assembly contents must be explicitly saved with the shipment so that they may be viewed at a later date, independent of the state or mere existence of the assembly in the user's defined inventory (that being, the items table).
It is storing the assembly contents along side the shipment contents that has me a bit confused, and where it seems to me that storing the data in JSON is a visable solution. It is critical to understand the following points about this data:
It will NOT be used for Searches
Any UPDATES will simply overwrite the contents of the row
It will MOST OFTEN be used to populate a Tree View on the Client, which will accept the JSON as it exists in the table, without any need for modification.
See this image for a (hopefully) more clear visualization of the data:
Questions
Is this a reasonable use case? Are my concerns meaningless?
Is there anything that I have looked over that may come back to bite me?
Can you provide an explanation why I should NOT proceed with my proposed schema, and if so....
Can you provide an alternative approach?
As always, thank you so much for your time and please do not hesitate to request clarification or additional information.
UPDATE
As per #Rowland Shaw's suggestion (below), I've come up with another proposed table structure using a reflexive or "bunny ear" relationship to the order_assembly_contents table. Please see the following image:
I feel this is a lot more elegant than storing the JSON directly, as the data is more relational and database friendly. Retrieving the data and forming it for the client should be easy-peasy as well! Please provide any input on the above structure!
Typically, for an ordering system I'd expect something like
Product -< OrderLine >- Order
In your case, you could add a "bunny ear" relation on your Product to refer to itself. So your outbound_shipment_contents loses name, type to the new product. You can then recursively build up the tree of items to pick as required.
This appears to be a standard bill of materials problem and there are lots of good articles on SQL and bill of materials patterns. I would avoid the JSON storage as it really complicates any reporting and detailed joining functionality that relies on the native SQL. For your application you can construct the JSON for the UI within a data access layer.
IMHO: Keep the data clean, highly accessible and relational in the relational db, repurpose for the application at the data access/low level business layer.

Good architecture for app with variable list of attributes

We are breaking a large asp.net web forms app into chunks and one of the pieces will be rebuilt using asp.net mvc. There are 2 primary types of orders (lets say types A and B). Each order has secondary types (lets say A1,A2, B1, B2, etc.) and each order has attributes. Type A* orders share almost all of the attributes and Type B* orders share half of all the attributes. From the order history we found most of the orders placed were of Type A. The current design uses user controls for the order form for each secondary order type so there is user control for A1, another for A2, etc. The attributes are fields in these user controls.
As part of the redesign we wanted to see if we can get away from user controls and instead generate the order form with the necessary attributes dynamically while keeping the app lightweight and also be able to add a new secondary order type with minimal effort.
Design 1: Create a table with all possible attributes and map them to each secondary type and turn on/off attributes? It could get very granular and include information about how an attribute should be rendered.
Pros: Adding secondary order type is easy, just need to add mapping for new order type.
Cons: Adding new attributes will requires changes to mapping table and perhaps all the layers. May need an admin section to manage mappings.
Design 2: Use jquery templates to replace user controls, send up json to the server.
Pros: Easy to add new form for a new secondary order type.
Cons: some logic may have to go into the templates (views)
Any advice on which one of these is a good design? Is there a better way?
Thanks.
Your database design has nothing to do with ASP.Net or JQuery. You need to worry about building a solid data model.
Table Inheritance and a good ORM will help here.
http://martinfowler.com/eaaCatalog/singleTableInheritance.html
https://community.jboss.org/wiki/NHibernateForNET

CakePHP alternative to Class Table Inheritance?

I want to create a Class Table Inheritance model in CakePHP.
I would like to have a Model called something like ProductBase with the table product_bases to hold all the base information every product should have, like upc, price, etc.
Then have specific product type models extend that. For example ProductRing with the table product_rings to hold specific ring information like ring_size, center_stone, etc.
Then if I retrieve data directly from the ProductBase model, have it pull all types:
// pull all product types
$this->ProductBase->find('all');
Or find specific types only:
// pull only Rings or descendants of the Ring type.
$this->ProductRing->find('all');
Is anything like this possible in CakePHP? If not, what should I be doing instead?
What is the proper Cake way of doing something like this?
I worked with CakePHP for two years, and found no satisfactory solution for this, so one day I wrote a solution for it. I built a new kind of ORM that work as a plugin on top of CakePHP 2.x. I called it "Cream".
It works similar to the entities of CakePHP 3.0, but in addition supports multi table inheritance. It also supports very convenient data structure browsing (lazy loading) and is very easy to configure. In my opinion it is more powerful than what CakePHP 3.0 offers right now. Data structure browsing works as follows:
$entity = new Entity('SomeModel', $somePrimaryKeyValue);
$foo = $entity->RelatedModel()->YetAnotherRelatedModel()->someProperty();
However, it is important to notice, that in Cream, each entity object is a compund of a series of models and primary key values that are merged together. At least in the case where model inheritance is used. Such a compound looks like:
[<'SomeConcreteModel', primaryKeyValueA>, <'IntermediaryModel', primaryKeyValueB>, <'BaseModel', primaryKeyValueC>]
It is important to notice that you can pick up this entity by any of the given model/primaryKeyValue combinations. They all refer to the same entity.
Using this you can also solve your problem. You can use standard CakePHP find methods to find all primary key values you want from the base model, or you can use the find methods models that inherit from it, and then go along and create the entities.
You set up the chain of inheritance/extension by simply writing in your model class:
public $extends = 'YourBaseModel';
In addition you also needs to setup an ordinary CakePHP relationship between the models (hasOne or belongsTo). It works just like in normal OOP, with a chain of models that inherit from their bases. If you just use vanilla CakePHP you will just notice that these models are related, but when you start using the Cream interface, all entities merge model/primaryKeyValue pairs into one single object.
Within my github repository there is a powerpoint file that explain most of the basic features.
https://github.com/erobwen/Cream
Perhaps I should fork the CakePHP project and make a pull request, but for now It is a separate repository. Please feel free to comment or participate in developing "Cream".
Also, for those suggesting that it is best to just "work with the CakePHP flow as intended" I would argue the following. Common estimates suggest that C programs are 2.5 times bigger than the C++ counterpart. Given that the only feature that separates these languages is the OOP with inheritance etc, we can deduce that the lack of proper OOP with inheritance etc requires the programmer to do 150% additional work with repetition code etc. Therefore I would argue that a proper model inheritance mechanism in CakePHP is very much needed. Cream is an attempt at this.
You are referring to an ARC relationship (or at least a variation of it). Cake does not handle these types of relationships on the fly. This means you will have to implement your own logic to handle this.
The other option is to categorize the products. If the product can fit into multiple categories, then you will want a HABTM categories for each product. Otherwise, you can use a category column. I suspect it will be a HABTM you are looking for.
PRODUCTS: The table that holds the
products.
CATEGORIES: The list of categories
any given product can belong to.
CATEGORIES_PRODUCTS: The link between
each product and their various
categories.
TYPE: This is the flag that will
define the type of product (i.e.
ring, shoe, pants, etc.)
Then when you want ALL products, you query the products table. When you want a slice of the products (i.e. Rings) you select all the products that belongs to the RING category.
Now, we need to address the information about the product. For example, not all information will apply to every product. There are a number of ways to do this.
You can build multiple tables to
hold the product information. When
you pull a product of a given type,
you pull its companion information
from the table.
Store the information in a text
field as serialized data. All of the
information can be defined in a
settings var and then you can use
the serialized data to map to the
information.
I hope this helps. Happy coding!