So if I have users and address tables. Because each users can buy or sell things so in the users table should have return_address, shipping_address, and billing_address. Then how can I define the relationship of these two tables?
Many-to-Many: because multiples users have multiple addresses (different type of address).
One-to-One: because each user only have one address.
One-to-Many: many users can share one address.
After reading some tutorials about hibernate, I find myself so confusing because now it has Many-to-One (I understand that it is a reversion of One-to-Many, but still confusing) .
Would any one mind to give me some advises and suggestions designing the database as well as optimization the database/query performance? It would be wonderful to help a new learner like me reduce the headache.
Thank you in advance.
User table will hold the address key.
#Entity
public class Customer{
#ManyToOne
#JoinColumn(name = "return_address_fk")
private Address returnAddress;
#ManyToOne
#JoinColumn(name = "shipping_address_fk")
private Address shippingAddress;
#ManyToOne
#JoinColumn(name = "billing_address_fk")
private Address billingAddress;
}
#Entity
public class Address{
// address properties
}
** Do not get confused.
Address should be a referred entity, means it's lifecycle does not depend upon User.
1.) Many users can have same returnAddress.
2.) Many users can have same shippingAddress.
3.) Many users can have same billingAddress.
If you say, One user can have Many returnAddress, shippingAddress, billingAddress, then add Many To Many annotation. Separate table will be created.
Related
I have the following class model:
I must make sure that an employee only has one role belonging to a project. So if Project A has the roles roleA and roleB, then the employee is only allowed to have one of them(but hes obviously allowed to have a role from another Project, but again, only one).
I make sure that thats always the case in my business logic. So before i add a role to an employee, i check whether the employee already has a role which belongs to the project of the role he wants to add, etc. So using my API/business logic, im able to make sure that the must criteria is fullfilled.
But should i add an extra layer of security on the database level? I could add triggers which check the above mentioned criteria. That would make it absolutely impossible to add any data into the database which violates my criteria. Is that extra layer of security on database level needed or is it enough if i do the validation in my business logic? And is a trigger the correct best way to do it?
Edit:
I implement what the comments suggested the following way:
My IdClass implementation:
#Data
public class TestId implements Serializable {
private Project project;
private Employee employee;
}
The class implementing the ternary association, making the employee and project pair unique:
#Entity
#Data
#IdClass(TestId.class)
public class Test {
#Id
#ManyToOne
private Project project;
#Id
#ManyToOne
private Employee employee;
#ManyToOne
private ProjectEmployeeRole projectEmployeeRole;
}
There are two questions in one.
Database: If you want the database to enforce this rule, you do not need any trigger. Just implement the many-to-many relation between Employee and Project using an association table with a primary key made of EmployeeId and the ProjectId: the combination must be unique. In the association table you'd also store the sole role this employee would have on that particular project.
UML class diagram: your diagram is misleading, since there are a lot of many-to-many association, but unfortunately, you say that one particular role can appear only in one project. A clearer way to represent this in UML would be to represent a ternary association (the association table I mentioned for the database would in fact impelment this ternary association). Another variant would be to use an UML association class and this association class could itself have an association with the role.
I've got 3 classes, one superclass and two subclasses. Each subclass has a collection of the other subclass and I want to map a one to many relationship between them. My superclass is person, and the subclasses are called referrer and broker. The relationship I want to represent is that one referrer can have many brokers and that one broker can have many referrers.
#Component
#Entity
#Table(name="Referrer")
#PrimaryKeyJoinColumn(name="rowID")
public class Referrer extends Person implements Serializable{
private static final long serialVersionUID = 972571370198603227L;
#Column(name="rowId")
private String referrerID;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn
private List<Broker> brokers = new ArrayList<Broker>();
And broker looks like this:
#Component
#Entity
#Table(name="Broker")
#PrimaryKeyJoinColumn(name="rowID")
public class Broker extends Person implements Serializable {
private static final long serialVersionUID = 5648239413711716027L;
#Column(name="AdminID", nullable=true)
private String adminID;
#Column
private boolean isAdmin = false;
#OneToMany(cascade=CascadeType.ALL, mappedBy="referrer")
private List<Referrer> referrers = new ArrayList<Referrer>();
The primary key for Broker should be a field called rowID that is contained within the Person superclass.
I'm really stuck, so any help would be greatly appreciated.
In the end what you have here is a ManyToMany relationship. One question aside, are you using a join table? It looks like thats the case. Basicaly what you try is this:
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(
name = "jointablename",
joinColumns = #JoinColumn(name = "FlexRowId"),
inverseJoinColumns = #JoinColumn(name = "FlexRowId")
)
private List<Referrer> referrers = new ArrayList<Referrer>();
Basically thats what you would need to add in both entities. Probably you can then ommig the #PrimaryKeyJoinColumn(name="FlexRowID"). But I have to admit that I don't know how it would work out using basicaly the same column for mapping on both sides. So please keep me posted on ho it works out.
If the primary key for Broker is in Person then my approach is this
Define one-to-one join relation ship between Person and Broker each having its own table
Use Person's PK in foreign-id generator for Broker (make it bi directional so that cascade will work fine)
Repeat the same for Referrer (it has its own table)
Introduce another intermediate table having two columns (of course with different names) composite PK of both tables (Broker and Referrer). Use many-to-many relation ship for Broker (and Referrer) and Join on respective PK columns on intermediate table.
Even after reading the documentation, I seem to have a fundamental misunderstanding about Google App Engine's entity groups. My goal is a trivial example of ORM: I've got some Employees assigned to Departments. An employee can only be assigned to one department, but a department can have many employees. It's your standard one-to-many relationship.
Given the employee's key (email) and a department name, I want to look up both the employee and department objects, and if they don't exist, to create them.
What follows is pseudocode, not meant to compile. If producing code that will compile would help you help me, I'd be happy to do so, but I think my problem is conceptual.
Data Objects:
#Entity
public class Department {
private Key key;
private String name;
// getters and setters
}
#Entity
#NamedQuery(name="getEmployeesInDept", query="SELECT a from Employee a WHERE a.dept=:dept")
public class Employee {
private Key key;
private String firstName;
#ManyToOne
private Department dept;
// getters and setters
}
Look Up or Create
Key employeeKey = KeyFactory.createKey("Employee", email);
Employee employee = entityManager.find(Employee.class, employeeKey);
if(employee == null)
{
Key deptKey = KeyFactory.createKey("Department", deptName);
Department dept = entityManager.find(Department.class, deptKey);
if(dept == null)
{
dept = new Department();
dept.setKey(deptKey);
dept.setName(deptName);
entityManager.persist(dept);
}
employee = new Employee();
employee.setKey(employeeKey);
employee.setFirstName(firstName);
employee.setDept(dept);
entityManager.persist(employee);
}
entityManager.close();
print("Found employee " + employee.getFirstName() + " from " + dept.getName() + " department!");
That's the logic that worked perfectly when I was using ye olde generic ORM before I tried migrating to Google App Engine.
However, on GAE, I get an exception like:
javax.persistence.PersistenceException: Detected attempt to establish
Employee("bob#mycompany.com") as the parent of Department(14) but the
entity identified by Department(14) has already been persisted without
a parent. A parent cannot be established or changed once an object has
been persisted.
While I understand that in order to get Employee and Department into the same entity group (which I would prefer), I have to make one of them the parent of the other, their relationship isn't really one that fits into the parent-child paradigm in my mind.
I have tried wrapping various parts between entityManager.getTransaction().begin() and entityManager.getTransaction().end(), but to no avail.
I can get around this by including Department's key as part of Employee's key (thus making Department the parent of Employee), but then I have no idea how to look up an Employee based on their email and figure out what department they're in, or, conversely, how to look up all the employees in a given department.
Does this make sense? How should I structure this relationship in GAE? Surely this is a very common pattern that has a simple solution that is just eluding me.
I'm convinced that there's some fundamental piece of this puzzle that I'm missing, because it seems rather ridiculous that a simple many-to-one foreign key cannot be easily represented in GAE's ORM.
Cheers!
So if it doesn't fit owned relationships then make it unowned, which is supported in v2.x of the GAE JPA plugin.
My background is in relational DB's and I am doing some experimenting with Google AppEngine primarily for learning. I want to build an "election" app where a user belongs to a state (CA, NY, TX, etc), they pick a party (Republican, Democratic, etc) and cast a vote for a particular year (2012 for now but the app could be reused in 2016).
I want a user to be able to see their voting history and maybe change it once for the current election. Also, I am going to require that users specify their zip code and think it would be nice to run some reports by state and/or zip code.
Using a relational DB, it seems you would create some tables like this:
Users(userid, username, city, state, zip)
UserVote(userid, year, vote)
And then use SQL to run reports. With the AppEngine datastore it seems that running aggregate reports is somewhat of a challenge.
My initial take would be to shard by User where each user can contain a list of Votes and then maybe double-save the aggregates elsewhere.
Any suggestions?
P.S. I have seen the AppEngine-MapReduce project, but am not sure if that would be overkill.
I dont remember exactly where I read this, but List properties in GAE become slow after they reach about 200 items. I would recommend against this in favor of the foreign key approach for Users and Votes.
Aggregates are a challenge since there are none of the common helper functions such as MAX, SUM, COUNT and so on. The best approach would be to store aggregates and counts in a separate datatype which you can query easily and update that every time a user makes a vote.
Its easier in AppEngine to spend the time when you do the write so you can have faster queries later.
Here's a example of the objects in Java:
#PersistenceCapable
public class User{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
...
}
#PersistenceCapable
public class Vote{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Key userKey; // References a User
...
}
#PersistenceCapable
public class UserStats{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Key userKey; // References a User
...
}
Also, traditional sharding doesn't make much sense in AppEngine since the underlying datastore is designed to handle queries on massive data sets with ease. The exception is if you have a specific counter that can be changed frequently and has a potential for multiple users changing it at the same time. This is a different type of sharding than you're used to in MySQL. Here is Google's article on sharding counters: http://code.google.com/appengine/articles/sharding_counters.html
I think my understanding of Django's FK and admin is a bit faulty, so I'd value any input on how to model the below case.
Firstly, we have generic Address objects. Then, we have User's, who each have a UserProfile. Through this, Users belong to departments, as well as having addresses.
Departments themselves can also have multiple addresses, as well as a head of department. So it might be something like (this is something I'm just hacking up now):
class Address(models.Model):
street_address = models.CharField(max_length=20)
etc...
class Department(models.Model):
name = models.CharField(max_lenght=20)
head_of_department = models.OneToOneField(User)
address = models.ForeignKey(Address)
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
address = models.ForeignKey(Address)
department = models.OneToOneField(Department)
Anyhow, firstly, is that the right way of setting up the relationships?
And secondly, I'd like it to appear in the admin that you can edit a department, and on that page, it'd have an inline list of all the addresses to also edit. I've tried setting up an AddressInline class, and attaching it as an inline to Department.
class AddressInline(admin.TabularInline):
model = Address
class DepartmentAdmin(admin.ModelAdmin):
inlines = [AddressInline]
However, when I try to display that, I get:
Exception at /admin/people/department/1/
<class 'people.models.Address'> has no ForeignKey to <class 'people.models.Department'>
Cheers,
Victor
Since it seems you want a UserProfile or Department to have potentially many addresses, your ForeignKeys are backward. A single ForeignKey can only point to one model instance, whereas there is no limit on the number of ForeignKeys that can point to a single model instance. So your ForeignKey should be on Address (in which case your inline would work as-is).
The complicating factor is that you have a single Address model and you want to relate it to two other models; a single ForeignKey on Address can't point to both UserProfile and Department. One solution is to have two address models (DepartmentAddress, with a ForeignKey to Department, and UserAddress, with a ForeignKey to UserProfile). You could reduce duplication in your code by having these both inherit from an abstract base class containing all the data fields, but you still end up with two mostly-identical tables in your database.
The other option is to have a GenericForeignKey on Address, which can point to an instance of any model. Your inline would then need to become a GenericInlineModelAdmin. This violates pure database normalization and doesn't allow your database to do proper integrity checking. If you had potentially more models in the future that would also have addresses, I'd consider this; if it's likely to be limited to only the current two, I might go with the above option instead.
I read your models what you want from your models as:
A department has one to many addresses
A department has one and only one user (as head of department)
A user (through his profile) belongs to one to many departments
A user (through his profile) has one to many addresses
If that was your intent, meaning that there is no case where a user will NOT have an address or a department, and no case where a department will not have an address or a head of department; then I would say your models are OK should read:
class Department(models.Model):
name = models.CharField(max_lenght=20)
head_of_department = models.OneToOneField(User)
address = models.ForeignKey(Address)
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
address = models.ForeignKey(Address)
department = models.OneToOneField(Department)
class Address(models.Model):
street_address = models.CharField(max_length=20)
...
class Meta:
abstract = True
class UserAddress(Address):
user_profile = models.ForeignKey(UserProfile)
class DepartmentAddress(Address):
department = models.ForeignKey(Department)
Read more about abstract classes.
What your models are not contemplating are the possibilities that two Users will have the same address, and/or that two departments will have the same address. Since you are not specifying a unique constraint on address (that I can see), I assume that you are OK with a real-world address showing up more than once in your Address table.
If that is OK with you; fine.
The error message you are getting is stating a fact: there is no foreign key in Address to Department. You will have to revert that relationship for the inline to work. Meaning, when editing an address you can edit any departments associated with it; but not the reverse. With the models I suggest above you should not see this error.
See the example from the docs. Notice how an Author has many Books and how the many side of the relationship is the one that can be inline.