Given the following JPA model:
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer")
private ShippingAddress shippingAddress;
//...
}
#Entity
public class ShippingAddress {
#Id
private long id;
#OneToOne
private Customer customer;
//...
}
This will create a foreign key to the customer table in the shipping_address table i.e. shipping_address.customer_id.
From a database point-of-view, one would say that customer is the parent table and shipping_address is the child table, because
An address cannot exist without a customer
If a customer is deleted, their address must also be deleted
However, according to JPA, the owner of this relationship is ShippingAddress because the JavaDoc for mappedBy states
This element is only specified on the inverse (non-owning) side of the association.
I find it extremely confusing that the owner of the relationship according to JPA is what (from the database point-of-view) would be considered the child table. Is there a way to reconcile this apparent contradiction?
In short: as posted before here and here, the owning side of the relation is the one that holds the FK in the DB table.
You can read this excellent answer for a full explanation why.
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 have a table which I need to delete from, but it has many foreign keys referencing it. I've never before used ON DELETE CASCADE - we have a kind of rule to soft delete records, or if a hard delete is absolutely required, to manually clean up any linked tables before/after deletion.
Is there a way, or a helper function somewhere, that will take a particular table (and record(s) in that table), iterate through every table/record in the database that is linked to it, and perform deletes. I want to believe for now that this isn't TOO bad a practice.
So, e.g. schema:
Organisations (OrganisationID, Name)
Users (UserID, FirstName, LastName, OrganisationID)
Projects (ProjectID, Name, OrganisationID)
Organisations_Markets (OrganisationID, MarketID)
Tasks (TaskID, Description, UserID)
If I wanted to delete where OrganisationID=3...
I know there's a way to list all the FKs in SQL - EXEC sp_fkeys 'Organisations'. How could I do this in EF, and do it for any nested FKs. So in the example above, the first deletes will be on the Tasks table (any records that are linked to Users where OrganisationID=3), and so on and so on.
edit: performance is not an issue - there'll never be more than 100 rows in total - so I'm happy to use EF for delete
In your model, it seems there are standard one-to-many relationships between Organization and Users and between Organization and Projects.
So every Organization has zero or more Users; every User belongs to exactly one Organization
Similarly every Organization has zero or more 'Projects, everyProjectbelongs to exactly oneOrganization`.
You also mention Organisation_Markets. You don't specify this, but it looks like a junction table for a many-to-many relation between Organization and Market: Every Organization refers to zero or more Markets; every Market refers to zero or more Organizations.
If you'd set-up the one-to-many and many-to-many relationships following the entity framework coding conventions you could safely remove an Organization.
Entity framework will automatically remove all Users and Projects from this Organization. All Markets that refer to this Organization won't refer to the deleted Organization anymore. But as it is allowed for a Market to refer to no Organization at all, Markets without Organizations won't be removed.
class Organization
{
public int Id {get; set;} // Primary key
// an Organization has zero or more Users (one-to-many):
public virtual ICollection<User> Users {get; set;}
// an Organization has zero or more Projects (one-to-many):
public virtual ICollection<Project> Projects {get; set;
// an Organization refers to zero or more Markets (many-to-many)
public virtual ICollection<Market> Markets {get; set;}
}
class User
{
public int Id {get; set;} // Primary key
// every User belongs to one Organization using foreign key
public int OrganizationId {get; set;}
public Organization Organization {get; set;}
}
class Project
{
public int Id {get; set;} // Primary key
// every Project belongs to one Organization using foreign key
public int OrganizationId {get; set;}
public Organization Organization {get; set;}
}
class Market
{
public int Id {get; set;} // Primary key
// every Market refers to zero or more Organizations (many-to-many)
public virtual ICollection<Organization> Organizations {get; set;}
}
class MyDbContext : DbContext
{
public DbSet<Organization> Organizations {get; set;}
public DbSet<User> Users{get; set;}
public DbSet<Project> Projects{get; set;}
public DbSet<Market> Markets{get; set;}
}
That's all. Because I followed the entity framework coding conventions, entity framework will recognize the one-to-many and many-to-many relationships and create the proper foreign keys. It will even create the junction table needed for the many-to-many relation, even though I didn't mention it.
By the way, I don't need the junction table. If I want all Markets belonging to an Organization I use property Organization.Markets. Entity framework will know that a join with the junction table is needed and will create the proper SQL code for it.
If you don't want the defaults, for instance different table names, consider using fluent-API or data annotations for this.
Now to remove an Organization do something like this:
using (var dbContext = new MyDbContext())
{
Organization organizationToRemove = dbContext.Organizations
.Where(organization => ...)
... etc.
dbContext.Organizations.Remove(organizationToRemove);
dbContext.SaveChanges();
}
Entity framework will automatically update other tables
All Users of the Organization are removed
All Projects of the Organization are removed
All references to the Organization in all Markets are removed.
So you don't need a special function to neatly clean up all references to the Organization you removed. Entity Framework will do this correctly for you.
Suppose my datastore model looks like this:
#Entity
public class User {
#Id
private Long id;
#Index
private String email;
private Long dateOfBirth;
// More fields...
}
#Entity
public class Topic {
#Id
private Long id;
private String topicTitle;
private Long date;
}
#Entity
public class Comment {
#Id
private Long id;
#Parent
private Key<Topic> topicKey;
private Long commenterId;
private String text;
private Long date;
}
Where the entity Comment has a parent entity Topic. I know one should store keys when specifying the #Parent such as I did in the Comment entity, but should one also store the key of the commenterId? Or is storing the Long id of that User enough?
Just wondering what the best practice is for storing references to other entities when they are not parents - should you store the id and generate the key later or just store the key to the entity. Is there a good reason why you might do one over the other?
EDIT: Since I am using Cloud Endpoints, the responses I get from my AppEngine project are JSON. Parameterized type of Key not allowed in the client libs. So for me, id can work and also Key<?> can work. Just note that you should return a websafe version of to your client using:
myKey.getString();
Typically there is no reason to store a key as a reference. Keys take much more space - both in the datastore, and in objects that you transfer to and from the client.
Using a key may be necessary only if the same entity kind can be either by itself or a child of another entity. It is technically possible, and some data models can use this approach, although it is probably a very rare use case.
NB: I only use ID of a parent in objects - for the same reason (less space). In datastore entities parent ID can always be extracted from a child entity key. I use low-level Datastore API, however - you need to check how to correctly annotate child-parent relationship in the library that you use.
I have a Person class in Contacts subsystem. On the other hand in CRM subsystem, I have the notion of Customer.
In database design, I want to create a relationship between these notions. There are some possible ways:
Each customer is a person, thus customer should inherit from person and customer dies as soon as his person is removed (Composition). In this case, we create a one-to-one relationship between Id columns of the Customers table and People table, and we make the Id column of the People table an identity field, but we explicitly insert the scope_identity() in the Customers table.
Each customer has a person, thus customer and person have their own life-cycles (Aggregation) and can survive without the other. In this scenario, Customers table should have a foreign key to People table. The bad point here is that each Person can have many Customers which seems odd to me.
Which design is suggested as the best practice? I need solid objective answers. Thank you.
There are different cases when you may or may not give each table it's own ID.
In your case, it would be better if customer table does have it's own ID.
Example:
Own Id in a many to many relation defining table is redundant, when it doesn't have any extra column associated apart from the tables it is joining. Consider a Teacher and Student table relation. They have a many to many relation. If there is a table named TeacherStudentRelation having only foreign key to Teacher and Student table then it won't need any extra OwnId field.
But in your case, a Customer table surely would have extra information associated like balance, purchaseList or anything like that. And it is highly likely that you would search into Customer table for some data. Here an OwnId of customer table would let you to index that table.
Briefly, do give Customer table it's own Id.
IHMO, every entity must have a proper ID. You write about foreign key to refer Person as Customer, but this is another concept.
If Person is a base class about Customer, so, the ID field is the same and you don't explicit in Customer class because it inherit by Person.
In the first case (Person and Customer with FK) you have:
class Person {
private String id;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
class Customer {
private String id; // this is different by id of Person class
private Person person;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
In the second case (Customer extends Person) you have:
class Person {
private String id;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
class Customer extends Person {
... other properties about Customer
... put here get and set property
}
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.