Database design for a product-configurator - sql

I have been asked by a customer to develop a "product configurator", and i need some inputs on how to handle the DB part of the project.
Each product can have a subset of different precreated attributes.
The minimum is 1 attribute, but there is no maximum.
Some attributes have dependencies/relationships with other attributes.
Eg. If the product is a chair, you need to choose the material (wood, plastic, metal), and you need to choose which type of legs the chair shoud have.
If the Product is a cabinet, you still need to choose a material, but instead of legs there will be different doors to choose from etc.
Each of these attributes might have subattributes. Eg. the door has a color, a size and a doorhandle.
Then the door handle has a material, a type and so on.
This ultimatly ends up in a multi-layered attribute-tree.
By itself this isnt too complicated to code, however the customer wants to be able to manage (Create, update and delete) all products, attributes and relationships between attributes, within the webapp.
So coding the relationship-part isn't a viable solution.
I have gone with a EAV model to facilitate the "potential unlimited" amount of attributes each product can have.
But i am struggling to figure out how to go about the "attribute relationships".
A simplified version of my DB design looks like this:

If each product could subscribe to groups of attributes that is legal. Then each attribute belongs to a group like "wood group".
Then the user could set the groups of attributes against a product that should need to be answered to configure a product.
With regards managing a tree, you could use a column type of hierarchyid . Or construct an outline string as key field.
An outline for example
1.
1.1.
1.1.1.
1.2.
2.
2.1.

Related

DDD - Entity vs ValueObject

I was reading about DDD and I realize that sometimes an entity might be a VO or VO might be an entity. You can know which one is better depends on the context. I was checking different examples. For example, shopping cart DDD example. Product is an aggregate root, Cart is an aggregate root and items is a entity of Cart, so if you want to add a product to the cart you would do something like this:
$cart->addProduct(id $id, $name, $price)
class Cart
{
private items;
function addProduct(ProductId $id, ProductName $name, ProductPrice $price) {
this->items[] = new Item(
new ItemProductId($id->ToString()),
new ItemName($name->ToString()),
new ItemPrice($price->ToString()),
new ItemCartId(this->id->ToString())
);
}
}
There are two reasons why I think it is a VO:
You cannot modify the value's item ( only if the product's
price has been modify there is a event that would modify its price).
The item doesn't have id, it's has a reference of the
product(ItemProductId) and a reference of the cart (ItemCartId)
I was reading about DDD and I realize that sometimes an entity might be a VO or VO might be an entity. You can know which one is better depends on the context.
Usually its pretty clear whats entity and whats an value object. If it contains data that's fixed at the time of assignation, its a value object. For example "order address" on the order aggregate. When the order is placed, the address is set. "Addresses" may be an entity in user aggregate (i.e. a list of his common addresses), but for an order its an value object since its not supposed to change when the user edits or deletes one of his addresses.
cart->addProduct(id $id, $name, $price)
class Cart
{
private items;
function addProduct(ProductId $id, ProductName $name, ProductPrice $price) {
this->items[] = new Item(
new ItemProductId($id->ToString()),
new ItemName($name->ToString()),
new ItemPrice($price->ToString()),
new ItemCartId(this->id->ToString())
);
}
}
That's a pretty bad example. Why would or should the value object be ItemPrice? Does that makes it any special? Why string? A price is usually just a numeric value but also involves a currency, passing it as string kinda beats that.
On top of that, having ItemCartId in the it does
a) leak data persistence knowledge into your domain. The fact, it's contained inside this->items[] already establishes a relationship between the entity (or aggregate) and the value object. ItemCartId as no meaning in the domain, other than that it's required for relational database engines (=persistence knowledge)
There are two reasons why I think it is a VO:
You cannot modify the value's item ( only if the product's price has been modify there is a event that would modify its price).
You sure? Why would a eCommerce business want to have the prices in the card anyways?
Prices are informational only, they could change before the order is placed. Same as availability.
A lot of users put stuff in their cart and check on next day. In that time, the price could change.
No company would want to sell a product for the price when it was put into the shopping cart, if the price increased in the time since it was put in there. That would mean a financial loss.
Prices in the shopping carts are informational, not compulsory. You need know the exact process of the company.
The item doesn't have id, it's has a reference of the product(ItemProductId) and a reference of the cart (ItemCartId)
Again. Why do you think ItemCartId belongs to the Item object? That's leaked persistence knowledge, since its only important for relational database systems.
All you really need in a shopping cart is
* product or article number (not necessary the id, that's typically db knowledge)
* quantity
Nothing else. If you may want to change the user when the price changed and show the old and new price, the take the price (=currency value object, not ItemPrice) to it too as a value to compare to an old state.
Finally and probably most importantly: Consider if the shopping cart is an aggregate at all (or does fit into ddd).
After all, most shopping carts are only a value bag w/o a lot of business logic into it. The real logic (checking the real price, product availability, asking for shipping location, calculation of taxes and shipping costs) happens during the checkout process, not while putting stuff into the cart.
For example you can check out eShops on Containers demo project showing an example shopping service based on microservices and ddd.
Some microservices apply DDD (such as Ordering microservice), where others don't (Catalog microservice or the Basket (cart) Microservice).
Applying DDD doesn't mean everything needs to be done with DDD. If its simple crud based services, then you don't need DDD for these. DDD adds a value where you have complex systems and complex business logic.
A catalog has neither, it just presents data which come from a different system (i.e. ERP which on other side may be built on using DDD).
I don't understand what are you asking exactly, but the code you are providing could be improved.
First of all I suggest you to read the red book by Vaughn Vernon https://www.amazon.co.uk/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577: you can find 3 chapters describing how to define entities, value objects and aggregates, with some rules of thumbs.
One of those advices, is to keep your aggregates as small as possible, in order to improve your performance and keep the code easy to read and maintain. Imagine that you have a Blog aggregate that contains a list of Post entities: if you manage all of them in a single aggregate, when you want to modify the blog Author, for example, you are forced to retrieve all of the blog's post, without any reason, and that means that you are doing a join and slowing down your application. The more your aggregates grows, the slower those queries with their joins.
So, in the case of the Cart, I suggest you to build the cart without any item or product, instead you can add the CartId to the Item. Cart does not know which items it contains, but items know in which cart they are.
About value objects: is a tool that allows you to wrap some validation and business logic inside a class that is represented by its state and not by its id (like entities), so in the case of the cart, if you put two identical bottles of water inside it, how can you know that they are different? Do you need to know that they are different? Are they different if they are physically (or logically different) or are they different if some of their attribute is different?
In my opinion an item or a product, in your case, are entities because they are not measuring anything, and when you put an item twice, you actually have two different items (and you use an id to recognize them).
This is not necessary like this, sometime you can use a value object and sometimes an entity, it depends on your context. A good example to understand that difference is with money:
if you want to measure an amount, for example 10 dollars, probably a value object will work for you, because you don't care if it a bill or another, you just want to measure 10 dollars; in this case if you have 10 dollars, is not important if you have a bill or another, the important thing is that is 10 and not 5
in the case that you need to recognize different physical bills, for any reason (you need to track money for the police), you should use an entity, because any printed bill has a unique serial number, and a 10 dollar bill, in this context, is actually different from another 10 dollar bill
Hope this can help you.
Goodbye!

Most appropriate way to store/retrieve User Input in a eCommerce iOS application?

I'm a bit confused with Sqlite, Core Data, NSUserDefaultsand PropertyList. I know what is what, but not a very clear idea of about where to appropriately use them.
I know that there are lots of tutorials, but I'm good at learning through situation based understanding. So kindly do help me to understand this in the situation that I'm facing right now and to make use of the available options wisely.
I'm working on an ECommerce iOS (native) application, where I'm highly dependent on API's for data display. Now I'm in need of recording user's review for a product and send it over through an API.
ie. I have three components, rating title, rating value(for that title) and another rating title ID. I'm defining with an example, I need to store multiple rows with details,
Components Data to be stored
**Title** - Quality | Value | Price
| |
**Rating** - 2 | 3 | 1
| |
**TitleID** - 10 | 11 | 12
Like this, there will be so many entries, i.e, the number of components differs for various users, for some users, there might be more than three components, which must be saved & send through an API. So how should I save these data? which is the RIGHT way to save these data temporarily?
If I understand you correctly, as vaibhav implied your question seems pretty general and probably relates more to structuring your data to fit your requirements than to technical aspects of the iOS / CoreData environment. In that vein, I’ll offer a few thoughts I’d have in structuring a data structure for quality ratings per your description.
If your ratings will always be for the three categories you show, i.e. Quality, Value and Price, I wouldn’t over-complicate things; I’d just use three properties in a rating record to hold the values that a user assigns in his/her rating of a product (just showing selected attributes and relationships in all following lists):
Product
name
Rating
ratedProduct (many to one)
qualityRating Int
valueRating Int
priceRating Int
Done this way you’d need to associate the values with their types in code for the APIs, such as (where item is a retrieved rating record):
display(product: item.ratedProduct.name, quality: item.qualityRating, value: item.valueRating, price: item.priceRating).
On the other hand, you may be describing a more generic approach that would allow for ratings categories that vary more frequently, or perhaps vary among products. This could apply where, for example, ratings include how well things fit for clothing but not for other products like books. In that case, you’d need a more complicated structure where a product could have a variable number of ratings of different types, so you’d need another layer of entities that let you create an arbitrary number of rating records that applied to a product.
Here you'd create a separate rating record for each rating that a user assigned to a product.
The simplest form of that structure would be like the following:
Product
name String
UserEvaluation
ratedProduct (many to one)
productRating (one to many)
ProductRating
ratingType (many to one)
value Int
RatingType
ratingTitle String
ratingID String or Int
Then you’d have to have a bit more structure where you'd list the product and then access the ratings with a loop that cycled through the set of all of the ratings linked to the product record somewhat like this (where item is a retrieved UserEvaluation):
displayTitle(product: item.ratedProduct.name)
for rating in item.productRating {
displayRating(ratingTitle: item.productRating.ratingType.title, ratingValue: item.productRating.value)
}
You'd probably want to combine these into a method that takes the name and an array of ratings.
To keep track of things, you’d also probably want to create another entity that defined product classes and specified what specialized ratings applied to each class (like fit for clothing and mileage for cars). By default, you also may want to allow for a few generic rating types that apply to all products (like the quality and price ratings you show). For this approach, the full structure would look like this:
Product Category
title
ratingType (many to many)
Product
productType (many to one)
UserEvaluation
ratedProduct (many to one)
productRating (one to many)
ProductRating
ratingType (many to one)
value Int
RatingType
ratingTitle String
ratingID String or Int
With this structure, once a product is assigned a productType, the application would know what ratings to ask for in the UI.
You could try building more complicated rating records with all of the types that apply to a product category, but that would get very messy if the applicable categories vary over time. You could also create a "custom" rating type that let a user specify a title and input a rating, in which case you'd need a text field in the rating record that only applies if the ratingType is "custom".
I hope this helps…

Ruby on Rails 3 - Modeling Products with Many Categories / Attributes

I am working on my first Rails website, a sort of shopping website: there are products sold through the website, each with multiple unique attributes.
The use case I am imagining is: a user visits the site looking to buy a used bed, they click through several higher categories until they find a bed of the correct size, something like this:
Furniture
---> Couch
---> Dresser
---> Bed
-------> Size
----------> King
----------> Queen
...
At each time the user clicks a more narrow category, they are supplied a menu with the next level of detail (a la NewEgg). When "Furniture" is clicked, all furniture is displayed, and a menu with the types of furniture appears. When "Bed" is clicked, all beds are displayed, and a menu showing the various attributes of a bed appears, etc.
So far, I have an "Item" parent class which contains all the attributes of every item sold through the website (price, description, etc...). I am stuck with what to do next.
My first instinct is to have subclasses, but they don't seem to be that useful. There is nothing about the "Furniture" subclass that would have anything new in it, other than definiting it to be furniture. Also, each parent class needs to know about its subclasses.
What sort of design pattern should I pursue to cleanly implement this model? I've been looking into nested sets, but I am not completely sure that's the way to go. Any guidance is appreciated.
Thanks!
Your categories clearly form a tree, which is probably why you're thinking about a class inheritance tree. However, you are correct that this isn't the right model, since subclasses do not add any functionality over their parents.
You should have a single "Item" class, which is a node in the category tree - with references to its parent category (another "Item", or null for the root) and its array of children (all "Item"s).
The correct place to store the information about the tree structure is the database. In your items table, add a "parent_id" column as a foreign key - to the items table.
As the user navigates down in the tree you show the subcategories by querying for the items whose parent_id equals the current item id.

How to name my enum elements?

I have a problem naming the elements in my application's data model.
In the application, the user has the possibility to create his own metamodel. He does so by creating entity types and a type defines which properties an entity has. However, there are three kinds of entity types:
There is always exactly one instance of the type.
For instance, I want to model the company I am working for. It has a name, a share price and a number of employees. These values change over time, but there is always exactly one company.
There are different instances of the type, each is unique.
Example: Cities. A city has a name and a population count, there are different cities and each city exists exactly once.
Each instance of the type defines multiple entities.
Example: Cars. A car has a color and a manufacturer. But there is not only one red mercedes. And even though they are similar, red mercedes #1 is different from red mercedes #2.
So lets say you are a user of this tool and you understood the concept of these three flavors. You want to create a new entity type and are prompted to choose between option 1, 2 and 3. How would you name these options?
Edit:
Documentation and help is available to the user. Also the user can be expecteted to have a technical/programming background, so understanding these three concepts should be no problem.
First of all let me make sure I understand the problem,
Here's what you have (correct me if I'm wrong):
#of instances , is/are Unique
(1,true)
(n,true)
(n,false)
If so,
for #of instances I would use single \ plural
for is\are unique (\ not unique) I would use unique \ ununique.
so you'll get:
singleUnique
pluralUnique
pluralUnunique
That's the best I could think of.. I don't know exactly who are your users and what is the environment, But if you have an option of adding tips (or documentation) that should be used for sure.

Need Help Writing SQL To Apply Promotions to Shopping Basket at Checkout

Don't laugh but I'm a Lotus Notes (non-relational database!) developer trying to work with SQL and, although I have the basic concepts nailed, I'm stuck on something I'd consider to be "advanced".
Imagine a user reaches an online checkout having added a set of products to their basket. I need to apply promotions to the basket.
These promotions look at the items in the basket and add "points" for any combination that matches a pre-defined "bundle". The promotions also need to be able to target users in specific countries (information gained at point of registration) and other personal details.
The promotions are entered and maintained by the site admin team and need to be as flexible as possible. So they can reward people for things like "Buy X products of type Y and get 50% extra points" or "3 or more XE-123s and get 500 points added" etc.
Right now I'm looking for general direction. How should I store the criteria that matches the items in a basket to any of the running promotions? Would one big Stored Procedure do or should the C# code that builds the basket loop through all promotions and see which fit?
Right now I don't even have a table schema. Just the knowledge of how it should work and little idea where to start.
Jake
My suggestion is to not use SQL for this sort of business logic.
The database is a good place to keep information about products like whether they are type Y or type X. This keeps the database design pretty straightforward.
What you mention about C# seems like a better direction. There is a lot of searchable information about 3-tier architecture that can help explain the benefits of this strategy well.
'As flexible as possible' is a red flag (IMHO). I'd try to nail that down to:
"Fixed-point and/or percentage (of total basket / bundle points) bonus (three columns in a helper table)
When the basket contains a combination that matches a pre-defined 'bundle', where 'bundle' is contained in a helper table, with multiply rows, with a bundleID and a row for each item in the bundle, containing at least ItemID and Quantity.
And no other kinds of reward possible. This to keep the project / requirement manageable.
Then have a SP which checks for the presence of bundles within the basket and applies relevant promotions (as stored in the first helper table).
Also make sure you know the requirement whether 1 or multiple promotions are possible.