Alternate design approach to #OneToMany unidirectional mapping not working in OpenJPA - database

Hello database experts,
Consider the following tables:
CREATE TABLE customers (
id INTEGER NOT NULL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
order_id INTEGER NOT NULL,
CONSTRAINT customers_ibfk_1 FOREIGN KEY (order_id) REFERENCES orders (id) ON DELETE CASCADE,
);
CREATE TABLE orders (
id INTEGER NOT NULL PRIMARY KEY,
date VARCHAR(100) NOT NULL,
...
);
Since most of my queries and needs in the application just require accessing the orders associated with a customer, I decided to go for a unidirectional One-to-many mapping from Customers to Orders, as multiple orders can be associated with a customer. I arranged the entity classes as follows:
public class Customer implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "id", referencedColumnName = "order_id")
private Set<Order> orders;
....
}
It compiles fine using JPA 2.0 and OpenJPA 2.4.0. However, throws the following exception at runtime:
...
nested exception is <openjpa-2.4.0-r422266:1674604 fatal general error> org.apache.openjpa.persistence.PersistenceException: The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.] with root cause
org.apache.openjpa.persistence.ArgumentException: You cannot join on column "customers.order_id". It is not managed by a mapping that supports joins.
When I looked around, looks like it is known bug: https://issues.apache.org/jira/browse/OPENJPA-1607 .
Did I miss anything here or does this mapping look okay? To get around this issue, I have 2 approaches as far as I can see:
Make the mapping bi-directional. However, as I read, in OneToMany bidirectional mapping, the ManyToOne is the owner. So in this case, the orders table will be the owner, which really isn't the case from a design perspective. There will be no orders, without a customer.
Add a ManyToOne uni-directional mapping from orders to customers table and for any queries for all the orders for a particular customer, just query the orders table with the customer id. Of course, this will mean multiple queries for what should have been a single query.
So my question around the design is: which approach do you think is cleaner and more efficient? Is there a better different approach altogether? Is there any performance or any other benefits of using unidirectional mapping instead of bidirectional mapping? I looked around, but could not find many articles on it. Not sure if I missed it. If there are not many benefits, then I may be better off with approach 1.
I apologize if I missed something. Any pointers are greatly appreciated. Thank you for your time in advance.
thanks,
Alice

Got this working, posting the answer as it may help out some one else.
Turns out one-to-many unidirectional mapping does work in OpenJPA as long as you specify a Join table. I too was seeing the issue as specified in the bug: https://issues.apache.org/jira/browse/OPENJPA-1607 . However, once I added a Join table, it worked like a charm. Of course, it does mean that I will have to add an extra table, but it greatly reduces the amount of code and error for updates and deletes. Once we get to the performance, I will see how it performs. But for now, this is it for me. Below is the snippet:
public class Customer implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "customers_orders",
joinColumns = { #JoinColumn(name = "customer_id", referencedColumnName = "id") },
inverseJoinColumns = { #JoinColumn(name = "order_id", referencedColumnName = "id") })
private Set<Order> orders;
....
}

Related

Abstracting Differing Implementations With A Single Table

The problem I am trying to solve is not an overly complicated one but one that I would like to try and solve more elegantly than I currently am.
Problem:
We do business with multiple companies. For the sake of argument lets say each company produces motor vehicles. Each company has a differing implementation (i.e. data that must be persisted into a database). When a customer orders a car, you have no way of knowing what type of car they might buy so it is desirable to have a single looking table called 'Vehicles' that establishes the relationship between the CustomerId, a unique VehicleId, internal to our database, globally unique and some sort of composite key which would be unique in one of the many CompanyX_Vehicle tables.
An example would be:
Top level lookup table:
VehicleId
CustomerId
CompanyId
CompanyVehicleId
CompanyAVehicle Table:
CompanyAVehicleId ------> Part of composite key
CompanyId ------> Part of composite key
...... unique implementation and persistence requirements.
CompanyBVehicle Table:
CompanyBVehicleId ------> Part of composite key
CompanyId ------> Part of composite key
...... unique implementation and persistence requirements.
I have to disable foreign key enforcement for obvious reasons however in code (in this case C#, EF), I can perform a single query and eagerly include the necessary data from the correct CompanyXVehicle table.
Alternatively, I can omit any kind of relationship and just perform two queries each and every time, one to get the company and companyvehicle ID's and then make a call into the necessary table.
However I have a feeling there is a better alternative to either of these solutions. Does anyone have a suggestion on how to tackle this particular problem?
I'll put an answer........so this can be closed out (eventually and if no one else puts a better answer).
While there are several ways to do this, I prefer the DRY method.
Which is :
Base Class/Table has the PK and all the scalars that are the same.
A different sub-class(table) for the different "types" of entities. This would have the scalars that are unique to the type.
Animal(Table)
AnimalSurrogateKey (int or guid)
Species (lookup table FK int)
Birthddate (datetime, null)
Dog(Table)
ParentAnimalSurrogateKey (int) PK,FK
BarkDecibels (int)
Snake(Table)
ParentAnimalSurrogateKey (int) PK,FK
ScaleCount (int)
Something like that.
ORMs can handle this. Hand/Manual ORM can handle it....
You can query for general information about the "Animals".
Or you'll have multiple queries to get all the sub-type information.
If you needed to query about basic information about just Dogs, it would be
Select AnimalSurrogateKey , Species , Birthdate from dbo.Animal a where exists (select null from dbo.Dog d where d.ParentAnimalSurrogateKey = a.AnimalSurrogateKey )
..........
The key is to follow an established "pattern" for dealing with these scenarios. Most problems have already been thought out........and a future developer will thank you for mentioning in the comments/documentation "we implemented the blah blah blah pattern to implement".
APPEND:
(using info from http://www.sqlteam.com/article/implementing-table-inheritance-in-sql-server)
That is a great article going through the scenarios. Again, you'll have to judge if EF is "good enough" or not........if it isn't, then you can manually do your ORM ... and (to get around the multiple queries concern) ... maybe test a query like this .........
select p.PersonID , p.PersonTypeID , s.EnrollmentDate , t.HireDate , par.DifficultyScore
from dbo.People p
left join dbo.Students s on p.PersonID = s.PersonID
left join dbo.Teachers t on p.PersonID = t.PersonID
left join dbo.Parents par on p.PersonID = par.PersonID
And then you can manually do your ORM to "switch/case" off of PersonTypeID, and create your subclasses using the data unique to each subclass (noting that the rows where the type is off, you will have null values.......ex: if your subtype is "Student", then par.DifficultyScore will be null for that row. )
At some point, you're gonna have to POC (proof of concept) your choice. You have a problem, there are a handful number of ways to deal with it....you have to test it. EF may be good enough..it may not be. Thus why I go POCO first...so I can go with ado.net/old-school/idatareaders if EF isn't performing well enough.
Good luck.

GAE datastore foreign key and join

i'm struggling with gae for something that looks very simple to me.
let me explain.
i have a table with data about a person, i decided to use email as id
#Entity
public class Person{
#Id
#Column(name = "email")
String email;
...
what i would like to accomplish is
create a table with two columns, both containing email from Person, with the meaning "email in column 1 has written to email in column 2"
when i delete a row from Person, i would like that all the rows in the table at point 1 that contain this Person email in column 1 or 2 would be deleted as a cascade effect
i want to query my database so that, given an email address, i will be able to join all the rows in the table at point 1 and extract all the datas (name, phone...) of the Persons the given email has written to.
trouble is that apparently in gae i cannot use join, and i simply can't understand how to create a join table with cascade effect.
any help is welcome.
thanks in advance
Datastore isn't a relational database, so you should familiarise yourself with the concepts before starting to design a solution. What you're trying to do is fit a square peg into a round hole: not only will you find you're missing joins, you will also have to implement your own cascade-on-delete (hint: you may not want to do this but if you did, and you have a lot of data, look at Task Queues).
You don't provide much in the way of code, and I don't know JPA (tip: look at Objectify, it's much more suitable for the non-relational Datastore) but you might want something like this (using Objectify annotations):
#Entity
public class Person {
#Id
String email;
...
}
Then I'm assuming you will have some kind of Message entity (what you refer to as a two-column table):
#Entity
public class Message {
#Id
Long msgId;
#Index
Ref<Person> from;
#Index
Ref<Person> to;
...
}
Depending on what queries you need to perform, you may need to create a custom index (read here). Remember, queries on Datastore are index scans.
But, say, you want to get messages sent from Person A to Person B, you can do something like:
Person a = ofy().load().type(Person.class).id("a#example.com").now();
Person b = ofy().load().type(Person.class).id("b#example.com").now();
...
ofy().load().type(Person.class).filter("from =", Ref.create(a)).filter("to =", Ref.create(b)).list();
Instead of using Ref<Person> (essentially a Key), you could of course use a String representing the email. You may also not want to use email as the #Id as that would prevent a user changing their email address.

Grails domain without primary key

Anybody knows how to map grails domain class to MSSQL entity witch has not primary key
class BRCategoryInt {
String lang
String name
static hasMany = [category: BRCategory]
static constraints = {
}
static mapping = {
table "brCategoryInt"
version false
//id column: ""
category column: "CategoryId"
lang column: "Lang"
name column: "Name"
}
}
In legacy database we have not primary key, just have an one FK CategoryId.
Any help will be very appreciated.
You should really always have a primary key on your data and I would recommend adding one just to keep everyone happy. If you cannot simply add a auto-increment id to your table you could use a composite key. See documentation here. If you cannot do this either then I would consider re-thinking how youe data is laid out.
You cannot map such domain in Grails. To read/write such legacy tables try groovy Sql.
It is my understanding that in theory it is possible to map to a table without a primary key, however I have yet to see it actually done. I have struggled with attempting it for days with nothing to show.
Short answer: Not possible in the current version of Grails.

A Simple One-To-Many Relationship in JPA on Google App Engine

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.

Multiple join associations in hibernate

My question is related to database design and also how to model that design in Hibernate. I have two tables with the following primary keys:
BLOCK (BLOCK_ID)
BLOCK_SHP (BLOCK_ID, SHAPE_VERSION)
BLOCK to BLOCK_SHP is a one-to-many relationship as a single block can have many different versioned shapes associated with it. So far so good.
The second association is that I also want to be able to get the current shape for the Block. To do this, I have added another attribute to the BLOCK table:
CUR_SHAPE_VERSION
BLOCK_ID and CUR_SHAPE_VERSION now form a foreign key to the BLOCK_SHP table on BLOCK_ID, SHAPE_VERSION. Each block may have 0 or 1 current shapes.
In Hibernate, I have set this second association up in the following way:
#OneToOne( cascade = CascadeType.ALL, optional = true )
#NotFound( action = NotFoundAction.IGNORE )
#JoinColumns( {
#JoinColumn( name = "BLOCK_ID", referencedColumnName = "BLOCK_ID", insertable = false, updatable = false ),
#JoinColumn( name = "CUR_SHAPE_VERSION", referencedColumnName = "SHAPE_VERSION", insertable = false, updatable = false ) } )
public BlockShape getCurrentShape() {
return currentShape;
}
The #NotFound annotation was required because Hibernate was having trouble dealing with nullable one-to-one associations. If it doesn't find the association it ignores it instead of throwing an error.
This isn't very satisfying to me though, because it means that Hibernate isn't really aware of the proper relationship between the entities. For example, if I query for currentShape is not null, Hibernate does not know how to perform this query properly - it is querying on block_id is not null or cur_shape_version is not null.
So I guess I have a few questions. First, is there a better way to model this second association in the database? Second, is there a better way in Hibernate to set up the annotations for it to better understand the relationship and be able to properly query on the shape table?
Thanks for any help.
The easiest way is to use a surrogate primary key for the Shape entity. The tables would look like this:
BLOCK (BLOCK_ID primary key, CURRENT_SHAPE_ID foreign key references SHAPE.SHAPE_ID)
SHAPE (SHAPE_ID primary key, SHAPE_VERSION, BLOCK_ID foreign key references BLOCK.BLOCK_ID)
The use of composite keys is discouraged by Hibernate, for good reasons (and the problem you're having is just one of them).

Resources