Right now my database has the following (simplified) format:
ShoppingList
{
List<ListProduct> listProducts
}
ListProduct
{
int quantity
Product product
}
Product
{
information about the overall product...
List<StoreProduct> StoreProduct
}
StoreProduct
{
information about the specific product and the store
}
In general, a shoppinglist contains a list of listproducts which each contains their quantity and their product which each contains a list of storeproducts.
This all works great - however, in my shoppinglist I wanna keep track of which storeproducts were purchased. Now I can't just add a "purchased" boolean to my storeproducts since they are used across multiple shopping lists (static information).
I thought of adding a purchasedProduct property of ListProduct which would be set to the purchased storeProduct and otherwise be null.
However I'm unsure as to whether there exists any better solutions? My schema is complex already so I'd don't want to make it even more complex if it isn't necessary.
UPDATE:
Here's my customer table:
Customer
{
List<ShoppingList> shoppingLists
}
Why don't you make a new table with something like CustomerID column references to Customer and another column references StoreProduct. Use that to store all the purchased product. I would suggest you to list the Schema related to Customer for this kind of question.
Related
I'm working on a project of mine and I have encountered a problem. Let's suppose that we have three classes (models) respectively Person, Shop, Transaction: the first and second one (Person and shop) are both interacting by creating and pushing in arrays an instance of Transaction. They all look as follows :
Person
{
firstName:String,
lastName:String,
transactions:[ref:Transaction],
...other properties...
}
Shop
{
name:String,
customers:[ref:Person]
transactions:[ref:Transaction],
...other properties...}
}
Transaction
{
from:ref,//id of person||shop
to:ref, //id of person||shop
amount:float
...other properties...
}
Now when some one opens and ask the app for the balance (money they have) he/she should see a list of transaction and the name of the either of the two other class... so normal populate or lookup won't do cause in the two different collection the id's might be the same so one of the way I wanted to address it was by creating an extra id that would be used when creating any of the Person and Shop instance thus any will have its own id (example: person.id-> 1,shop.id->2). But we would do first a query on id in the Person collection and then if this result is null we would then perform the second query on id in the Shop collection... I don't really like this solution so if anyone reading this have a solution please share it with me ... Thanks in advance
Edit: The Person instances may also send transactions to one an other
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).
The structure of concerning tables is as follows (MySQL):
//Table Name : team
tid PK
team_name (varchar)
//Table Name : fixture
fid PK
home_team_id FK |_ both referenced to 'tid' from 'team' table
away_team_id FK |
My aim is to retrieve the team names. Considering this structure, I think I'll have to retrieve home_team_id and away_team_id and then do something like
Fixture::where('tid','=',$home_team_id)->get();
My question is, is this the correct way to accomplish what I aim to do?
and
should this be done from the controller? (if so, then I'll have to do two queries from same function)
First, rather than having your primary keys be tid and fid, just keep them both as id. This is not only best practice, but will allow you to more easily use Laravel's Eloquent ORM as it by default assumes your primary key column is named id.
Second thing, make sure your table names are in plural form. Although this is not necessary, the example I'm about to give is using Laravel defaults, and Laravel assumes they are in plural form.
Anyway, once you've 'Laravelized' your database, you can use an Eloquent model to setup awesome relationships with very minimal work. Here's what I think you'd want to do.
app/models/Team.php
class Team extends Eloquent {
// Yes, this can be empty. It just needs to be declared.
}
app/models/Fixture.php
class Fixture extends Eloquent {
public function homeTeam()
{
return $this->belongsTo('Team', 'home_team_id');
}
public function awayTeam()
{
return $this->belongsTo('Team', 'away_team_id');
}
}
Above, we created a simple model Team which Laravel will automatically look for in the teams database table.
Second, we created model Fixture which again, Laravel will use the fixtures table for. In this model, we specified two relationships. The belongsTo relationship takes two parameters, what model it is related to, in both cases here they are teams, and what the column name is.
Laravel will automatically take the value in away_team_id and search it against the id column in your teams table.
With just this minimal amount of code, you can then do things like this.
$fixture = Fixture::find(1); // Retrieves the fixture with and id of 1.
$awayTeam = $fixture->awayTeam()->first(); // var_dump this to see what you get.
$homeTeam = $fixutre->homeTeam()->first();
Then you can proceed as normal and access the column names for the tables. So say you have a 'name' column in the teams table. You can echo out the the home team name from the fixture like so.
$fixture = Fixture::find(1); // Get the fixture.
echo $fixture->homeTeam->name;
It's nearly 2AM, so there might be an error or two above, but it should work.
Make sure you check the docs for Eloquent, especially the bits relating to relationships. Remember to name your columns and tables in the way Laravel wants you to. If you don't, there are ways to specify your custom names.
If you want to get even more fancy, you can define the inverse relationship like this on your Team model.
app/models/Team.php
class Team extends Eloquent {
public function fixturesAtHome()
{
return $this->hasMany('Fixture', 'home_team_id');
}
public function fixturesAway()
{
return $this->hasMany('Fixture', 'away_team_id');
}
}
Then to get all of a particular team's home fixtures...
$team = Team::find(1); // Retreive team with id of 1;
$homeFixtures = $team->fixturesAtHome();
I have the following problem with Django.
class UserProfile(Model):
inventory = models.M2M(InventoryItem)
class InventoryItem(Model):
item = GenericForeignKey()
class Equipment(Model):
base = GenericForeignKey()
Every user can have many items. Inventory item can point to equipment, materials and so on, but in this case it points to Equipment model. Equipment model has a relation to either Weapon or Armour or Accessory.
I need to remove a specific item from user's inventory.
UserProfile.objects.get(pk=1).inventory.objects.all()[0].delete()
** This also deletes equipment and weapon/armour/accessory objects related which is not intended. **
I have already added on_delete=DO_NOTHING on all foreign keys, but I do not see such option possible on GenericForeignKeys. What's the solution?
UserProfile.objects.get(pk=1).delete()
it looks like you're deleting the UserProfile, but not the specific item
Product product = new Product() {
Category = category
};
_session.CommitChanges();
vs.
Product product = new Product() {
Category.ID = category.ID
};
_session.CommitChanges();
What is the difference? Which one to use? Both seem to be valid and get correctly saved in the database.
Always use the first version. This will make sure all the relations are in a state they should be , because the keys and stuff are assigned and managed by the RelationshipManager.
I just pass Category.ID.
When the query is executed against the database the only information that is passed to Product is the Category ID, that is, this is the info that will be stored in DB (in each Product row).
Behind the curtains, the engine knows the fields necessary to generate the SQL insert command, in this case, only Category.ID is necessary when saving the Product. That's why no matter what option you choose, the save operation always succeeds.