Sales system datamodel (Logical) - data-modeling

I have tried to make a logical data model, but I am not totally sure if it is modeled right. It is a very cut-down and basic model, but overall I want to know if it is modeled the way is should be.
Furthermore, how do I convert this into a class model in object oriented programming?
I guess I need:
Class Customer: int id, string name
Class Order: int id, string date, Customer object
Class Item: int id, string itemName, string item Desc
Class OrderItem: ?

For your data model, you don't need the relationship line between Orders and Items. You're using the junction table Order_Items to represent that many to many relationship.
As for the class models, you won't need a class to model the junction table. You can simply model it with a collection of Item in your Order class. The relationship between the Order and Item class is a composition relationship. You can think of it as: An Order has-a Item or an Order has-s collection of Item.
Here is how you can model the Order class in java.
public class Order {
private int id;
private Date date;
private Customer customer;
private List<Item> items; // you could use other collection types as well.
...
}
Edit:
Also for your many side of the relationships, you may consider using "one through many" line (crows foot with a line)" as opposed to "zero through many" (crows foot with circle). A order generally has atleast 1 item and atleast 1 customer. An order isn't an order without a customer or items.

Related

JPA, Hibernate : Database Schema

This is my first post, so hi everybody! :)
I have a question regarding a schema of my database. I'm writing RESTful application using Spring. The idea is to allow user to create his own diet based on products stored in DB.
So I came to creating entity Meal, which should consist of Products and amount of those products. It seems like natural way to have something like this is using Map. Problem is, that as I have read there is a problem with mapping such class to JSON Object, which I would like to send to clients browser. My other idea was to store List of objects like ProductWithQuantity instead of such map, but I'm a little worried that DB would be quickly flooded by entries like 1 glass of milk, 2 glasses of milk, 1.1243 glasses of milk and so on.
So my question is - do you have any better idea for the schema for such purpose? ;)
I would define an entity Meal which has a oneToMany relation to an entity Product, this product has properties like 'name', 'amount' and 'unit' and 'price' or something like that. Unit can be "gramm", "liter" and so on.
I might suggest a Meal with many servings, each serving being of a single product. Products like Milk or Hamburg are likely to have nutritional information, while a Meal will have many servings of different products. Serving would essentially be a relational table between Mean and Product, but with additional information like serving size.
#Entity
Class Meal {
#Id
Integer Id;
#OneToMany(mappedBy="meal")
List<Serving> servings;
}
#Entity
Class Serving {
#Id
Integer Id;
#OneToOne
Meal meal;
#OneToOne
Product product;
#Basic
Long servingCount;
}
#Entity
Class Product {
#Id
Integer Id;
#Basic
String simpleName;
#Basic
Integer caloriesPerServing;
..
}

Using proper relations for product and attribute

I am about to implement a database for simple ecommerce platform. I want to implement the following:
Each product belongs to one product category;
Each product category has its own attributes;
Each product has one value for each attribute of this products type.
What relations should I use to store this kind of information?
Here is the logical model -- the way I understood it; you should be able to tweak it.
From this you can derive the physical model and the SQL code. The word KEY here means UNIQUE NOT NULL and you may use them for primary keys. Should you choose to introduce integers as primary keys, make sure you keep these UNIQUE.
Note that everything should be NOT NULL, once you get to the SQL.
Category named (CAT) exists.
Category {CAT}
KEY {CAT}
Attribute named (ATR) exists.
Attribute {ATR}
KEY {ATR}
Category (CAT) has attribute (ATR).
Each category has more than one attribute, it is possible for the same attribute to belong to more than one category.
CategoryAttribute {CAT, ATR}
KEY {CAT, ATR}
Product named (PRD) belongs to category (CAT).
Each product belongs to exactly one category, each category may have more than one product.
ProductCategory {PRD, CAT}
KEY {PRD}
KEY {PRD, CAT} -- seems redundant here, but is
-- needed for the FK from the next table
FOREIGN KEY {CAT} REFERENCES Category {CAT}
Product (PRD) from category (CAT) has attribute (ATR) that belongs to that category.
For each attribute that belongs to a category, that attribute may belong to more than one product from that category.
ProductCategoryAttribute {PRD, CAT, ATR}
KEY {PRD, CAT, ATR}
FOREIGN KEY {PRD, CAT} REFERENCES ProductCategory {PRD, CAT}
FOREIGN KEY {CAT, ATR} REFERENCES CategoryAttribute {CAT, ATR}
I don't know what database platform you are using, but for small numbers of products, and for queries that do not depend on the value of the per-category attributes, I'd use the following strategy:
CREATE TABLE "Category" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT
);
CREATE TABLE "Product" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"categoryId" INTEGER NOT NULL REFERENCES "Category" ("id"),
"attributes" TEXT NOT NULL
);
In this example, the categories are used mainly to enforce referential integrity and to provide a list of categories for navigation.
The attributes are stored inside the attributes column as JSON (most modern databases tend to support this natively).
If there are any attributes common to all types of products, we'd create specific columns in Product. For example, you could add creationDate, deletionDate, price, or whatnot.
This allows you to perform the typical Select * From Product Where id = #Id to get a specific product and Select * From Product Where categoryId = #CategoryId to get all products in a category.
A creationDate could be useful to sort the products by creation date and take the top N, if necessary, when filtering by category. However with small quantities like thousands of products you might as well get all products by category and do this in code.
Regarding the code aspect, products like Dapper have specific extensions helping you deal with these discriminated unions, but writing code to support it is fairly easy. Here's an how. I'll write pseudo-C#, but I'm sure you can adapt.
We have an abstract class taking care of the Product table rows
public abstract class ProductBase
{
// only the fields in the Product table here
public int CategoryId { get; set; }
protected string Attributes { get; set; }
// serialize extra fields to JSON in Attributes
protected abstract void Prepare();
// load the common fields from a data row
protected static ProductBase(DataRow dr)
{
CategoryId = int.Parse(dr["categoryId"]);
Attributes = dr["attributes"] as string;
}
// save to DB
public void Save()
{
Prepare();
// save to SQL
}
}
We also have specific classes per category which have the extra attributes and handle serialization and deserialization.
public class FooProduct: ProductBase
{
public string Color { get; set; }
protected override void Prepare()
{
Attributes = Json.Serialize(new { Color });
}
public FooProduct(DataRow dr): base(dr)
{
// we can only create foo products if the category is foo
if (CategoryId != 23) throw new InvalidOperationException();
var attr = Json.Deserialize(Attributes);
Color = attr.Color;
}
}
This idea works great while you don't need to get the "foo" products by Color. If you can afford to get all "foo" products and filter in code, great. If your database understands JSON and lets you query inside the Attributes field, good it will get slow with large numbers unless the server allows indexes to reference JSON-serialized values.
If all else fails, you'll need to create an index table which contains the color values and the ids of the products which have that color. This is relatively painful and you don't want to do it unless you need it (and you don't right now).

Database: item can have alternatives, how to link in database?

I have a database where I want to store multiple items, every item would be unique, but they can have alternatives from other makers. So items would have a potential M:M relationship with each other.
For example, item A could have 3 alternatives. If I add item B, the alternative, the link for the alternative item should also be reversed, so that when I search item B, I would find item A as an alternative. When I add item C, it should be added as an alternative for both item A and B, and C should have as it's alternatives item A and B.
How's the best/smartest way to make this relationship between a class of its own kind?
The way I'm thinking is making a table in between called alternatives with a unique ID for each new item, if an alternative is added, then it's linked to that parent ID (alternative ID) and thus no new ID would be made in the alternative table. If it's established only later that this is an alternative, then remove the alternative ID of one of the two and add the item to the other alternative ID.
public partial class Item : Entity
{
public Item()
{
Id = GuidComb.GenerateComb();
}
public Guid Id { get; set; }
public string ItemName { get; set; }
public string MakerRef { get; set; }
public string Description { get; set; }
public virtual Maker Maker { get; set; }
public virtual IList<Offer> Offers { get; set; }
//stuck here on the smart way to make the relationship with itself?
}
Any advice would be welcome!
Thanks in advance!
The suggestion I'm thinking about might be similar to what you proposed, but I'll try to formulate it in database terms.
As far as I understand your requirements, your alternatives relationship will be completely transitive. This means your item set is partitioned in equivalence classes of subsets containing mutually alternative items. (If an item has no alternative yet, the subset consists of this item alone.)
If that's true, then the most elegant and redundancy free way to represent this is to choose one of the items of such as subset as a representative of the entire subset. This is reflected by the following table design:
item(id, equivalence_id, other attributes, ...)
where equivalence_id is a foreign key to the representative. Each item gets born with an equivalence id of null. If it is made equivalent to another item,
if the item already present has an equivalence id of null, assign the id of this representative to the equivalence it of both items,
if the item already present has a non-null equivalence id, assign this to the equivalence id of the new item.
Note that this works, in case there are many items in the same equivalence class, no matter which of this items are used to link the new one.
Example:
id equivalence_id name
1 1 abc
2 def
3 1 ghi
4 4 jkl
5 4 mno
This means abc and ghi are equivalent, as well as jkl and mno, but def isn't yet equivalent to anything. Now if pqr comes along and should become equivalent to abc, it would get equivalence id 1. The effect is the same as making it equivalent to ghi.
To find all items equivalent to a specific one, query
select *
from item
where equivalence_id = :my_equivalence_id
If some information pertaining to the equivalence class as a whole should be stored, a separate table for the equivalence classes only should be created.

How to retrieve entities from datastore in reverse store order using objectify?

I have the following entity:
#Entity
public class ActionIndex extends EntityObjectAutoID {
#Parent Ref<Action> action;
#Id Long id;
#Index List<Long> receivers;
....
}
I want to retrieve the keys of the latest 10 entities that were added to datastore. But if I use this query:
ofy().load().type(ActionIndex.class).limit(10).keys().list();
of course I get the first 10 entities instead of the last 10. According to Objectify's doc:
You can sort on #Id properties if this query is restricted to a Class
which has no #Parent. Note that this is only important for descending
sorting; default iteration is key-ascending.
You can not sort on #Parent properties.
Since my class has a parent (and I need it to have it), what can I do to get the entities in reverse added order without having to add an extra timestamp property?
I found out how to do it. In order to sort by key, you just need to use __key__ as property. For filtering there is a convenience method called filterKey, but its equivalent for sorting (orderKey), as far as I can see, does not exist.
ofy().load().type(ActionIndex.class).order("-__key__").limit(10).keys().list();
--- Edit ----
Based on the comments below, it appears the use of a Date property is compulsory.

objectify query filter by list in entity contains search parameter

in an app i have an entity that contains a list of other entities (let's say an event holding a list of assigned employees)
using objectify - i need to find all the events a particular employee is assigned to.
is there a basic way to filter a query if it contains the parameter - kind of the opposite of the query in
... quick pseudocode
findAll(Employee employee) {
...
return ofy.query(Event.class).filter("employees.contains", employee).list();
}
any help would be greatly appreciated
i tried just doing filter("employees", employee) after seeing this http://groups.google.com/group/objectify-appengine/browse_thread/thread/77ba676192c08e20 - but unfortunately this returns me an empty list
currently i'm doing something really inefficient - going through each event, iterating through the employees and adding them to a new list if it contains the given employee just to have something that works - i know this is not right though
let me add one thing,
the above query is not actually what it is, i was just using that because i did not think this would make a difference.
The Employee and Events are in the same entity group with Business as a parent
the actual query i am using is the following
ofy.query(Event.class).ancestor(businessKey).filter("employees", employee).list();
unfortunately this is still returning an empty list - does having the ancestor(key) in there mess up the filter?
solution, the employees field was not indexed correctly.
I added the datastore-indexes file to create a composite index, but was testing originally on a value that I added before the employees field was indexed, this was something stupid i was doing - simply having an index on the "business" field and the "employees" field fixed everything. the datastore-indexes file did not appear to be necessary, after deleting it and trying again everything worked fine.
Generally, you do this one of two ways:
Put a property of Set<Key<Employee>> on the Event
or
Put a property of Set<Key<Event>> on the Employee
You could also create a relationship entity, but if you're just doing filtering on values with relatively low counts, usually it's easier to just put the set property on one entity or the other.
Then filter as you describe:
ofy.query(Event.class).filter("employees", employee).list()
or
ofy.query(Employee.class).filter("events", event).list()
The list property should hold a Keys to the target entity. If you pass in an entity to the filter() method, Objectify will understand that you want to filter by the key instead.
Example :
/***************************************************/
#Entity
#Cache
public class News {
#Id Long id;
String news ;
#Index List<Long> friend_list = new ArrayList<Long>();
// My friends who can see my news , exemele : friend_list.add(id_f1); friend_list.add(id_f2); friend_list.add(id_f3);
//To make an operation on "friend_list", it is obligatory to index it
}
/*************************************************/
public News(Long id_f){
List<Long> friend_id = new ArrayList<Long>();
friend_id.add(id_f);
Query<Nesw> query = ofy().load().type(News.class).filter("friend_list in",friend_id).limit(limit);
//To filter a list, just after the name of the field you want to filter, add "IN".
//here ==> .filter("friend_list in",friend_id);
// if friend_list contains "id_friend" ==> the query return value
.........
}

Resources