Fill JPA fill child array (one to many) with only certain children - sql

I need to fill a Entity with the children entities and it works well when I need all children but now I only want to have a few ones.
For example, I have Owner 1-----n Pet
If I ownerRepositoty.findAll(); I get all owners with each one having an array of all he's pets. But let's say I want to get all the owners with the pet array having only the ones which name starts with N.
Example of the parent entity:
public class Owner {
#OneToMany(mappedBy="Owner")
private Set<Pet> pets; //This gets filled with all pets
//getters & setters
}
And the child entity:
public class Pet {
#ManyToOne
#JoinColumn(name="owner_id", nullable=false)
private Owner owner;
//getters & setters
}
I tried with a JOIN FETCH as explained here in the repository query but It just made a normal sql JOIN which is not what I'm looking for.
Any ideas?

I found the way to do this:
You can use the #Where annotation to filter the childs of a one to many or a many to many relationship.
public class Owner {
#OneToMany(mappedBy="Owner")
#Where(clause = "name like 'N%'")
private Set<Pet> pets; //This gets filled with pets with a name starting with N
//getters & setters
}

Related

Filter on relationship's field

I'm trying to fetch all entities for a given relationship's field match (I want my entity's relationships filled out in the result). Trying with Filter on session.loadAll() to filter on the relationship's field but I can't make it work.
My entities definition looks like:
#NodeEntity
class ClockAction {
#Id #GeneratedValue
private Long id;
private String description
private User user;
private Office office;
}
#NodeEntity
class User {
#Id #GeneratedValue
private Long id;
private String name;
private List<ClockAction> clockActions;
}
#NodeEntity
class Office {
#Id #GeneratedValue
private Long id;
private String name;
private List<ClockAction> clockActions;
}
From that I'm need to retrieve all ClockAction entities where User.id is in a given set of Ids.
Here is my try :
Filter filter = Filter("id", ComparisonOperator.IN, userIds);
filter.setNestedPropertyName("user");
filter.setNestedPropertyType(User.class);
filter.setNestedRelationshipEntity(true);
return session.loadAll(ClockAction.class, filter);
This always returns an empty result. Any idea of what I'm doing wrong?
Using a session.query like this
session.query(ClockAction.class, "MATCH p=(a:ClockAction)-[r]-() WHERE id(r) IN {ids} RETURN nodes(p), rels(p), a, r ORDER BY a.id", params)
works but only office field of ClockAction gets filled out on the result entity, user is always null...
Any help is appreciated :)
Some things first:
It is unfortunately currently not possible to filter for an id field because the filters only work with properties. Id fields are queried in cypher with the id function. (id(n) != n.id)
You are not looking for a relationship entity (remove filter.setNestedRelationshipEntity(true);)
Now you have the choices:
Query for another property of the User class with the filter.
Alter your cypher query with something like this: "MATCH p=(a:ClockAction)-[r]-(n) WHERE id(n) IN {ids} RETURN nodes(p), rels(p), a, r ORDER BY a.id" The changes are based on the assumption that the code snippets are correct and User is not a relationship.
Additional information (edit):
If no relationship is defined, Neo4j OGM will create them directed outgoing from the node you are saving. Your graph could look like this (ClockAction as root):
Or like this (User as root with multiple ClockActions):
You are not getting the Office because your current query path is (:User)-[r]-(:ClockAction) there is no information in the path about an Office.
MATCH (n:User)-[ur:CLOCK_ACTIONS]->(c:ClockAction)-[or:OFFICE]->(o:Office) WHERE id(n) IN {ids} RETURN c, n, ur, o, or is a pretty straight forward query you could use. It removes the path centric style but also loads all the data you need.
If the graph was stored through the User but this is just an example and can be applied however the data looks in your graph, you won't see any User information on the ClockActions because as it saves without any hint Neo4j OGM will also expect the data related in a outgoing direction from the class you want to load.
Now it is necessary, keeping the User example, to add a #Relationship(type="CLOCK_ACTION", direction = "INCOMING") to the user field in your ClockAction class.
This will give Neo4j OGM the needed hint to put the User data it has in your user field.
I ended up following advises from #meistermeier and annotate my relationships giving direction.
Below is my model entities :
#NodeEntity
class ClockAction {
#Id #GeneratedValue
private Long id;
private String description
#Relationship(direction = Relationship.OUTGOING)
private User user;
#Relationship(direction = Relationship.OUTGOING)
private Office office;
}
#NodeEntity
class User {
#Id #GeneratedValue
private Long id;
private String name;
#Relationship(direction = Relationship.INCOMING)
private List<ClockAction> clockActions;
}
#NodeEntity
class Office {
#Id #GeneratedValue
private Long id;
private String name;
#Relationship(direction = Relationship.INCOMING)
private List<ClockAction> clockActions;
}
What #meistermeier suggested for query did not work for me, but gave me inspiration and I found this working fine :
MATCH p((u:User)-[ur]-(c:ClockAction)-[or]-()) WHERE id(u) IN {ids} RETURN p, rels(p)

NHibernate 4 child collection saved, but not re-loaded

I've got an NHibernate 4 project with several collection relationships. I'm unit-testing the object model, exercising all the collections. Most work fine, but in one case, the child collection is cascade-saved properly, but on loading the parent entity and examining the collection property, the child collection is empty.
Here are the abbreviated classes. GatewayUser is the parent object, and it has a collection of Student. The collection has a private backing property, and AddStudent/RemoveStudent methods.
Further complications: I'm using the NHibernate.AspNet.Identity library for OAuth2 user management, and GatewayUser inherits from IdentityUser. That in turn inherits from the the library's internal base entity class, which is different from my project's own base class.
public class GatewayUser : IdentityUser
{
public GatewayUser()
{
}
public virtual string FirstName { get; set; }
// ...More value properties and OAuth stuff omitted
// students associated with this user
private IList<Student> _students = new List<Student>();
public virtual IList<Student> Students
{
get { return new ReadOnlyCollection<Student>(_students); }
}
public virtual GatewayUser AddStudent(Student s)
{
if (_students.Contains(s))
return this;
s.GatewayUser = this;
_students.Add(s);
return this;
}
public virtual GatewayUser RemoveStudent(Student s)
{
if (_students.Contains(s))
{
_students.Remove(s);
}
return this;
}
Student is more ordinary; it inherits from my own BaseEntity class, has many value properties, and its own child collection of ProgramApplication items. Interestingly, this collection saves and loads fine; it's got the same structure (private backer, etc.) as the failing collection in GatewayUser.
The mapping is complicated, because the library internally maps its classes with NHiberante.Mapping.ByCode.Conformist classes (which I have no prior experience with).
I'm mapping my own classes with NHibernate automapping, because I have so many classes and properties to map. To get it all working, I copied the library's mapping helper class, and modified it a bit to add my base entity classes to it's list called baseEntityToIgnore. I also had to create a conformist mapping for GatewayUser, since it has a different base entity type, and my automapping wouldn't pick it up.
The unit test looks like this:
[Test]
public void GatewayUserCascadesStudents()
{
var u = new GatewayUser() { FirstName = "Mama", LastName = "Bear", UserName = "somebody#example.com" };
var s1 = new Student() { FirstName = "First", LastName = "Student" };
var s2 = new Student() { FirstName = "Second", LastName = "Student" };
u.AddStudent(s1).AddStudent(s2);
using (var s = NewSession())
using (var tx = s.BeginTransaction())
{
s.Save(u);
tx.Commit();
}
GatewayUser fetched = null;
int count = 0;
using (var s = NewSession())
{
fetched = s.Get<GatewayUser>(u.Id);
count = fetched.Students.Count;
}
Assert.AreEqual(2, count);
}
The generated SQL inserts into both AspNetUsers and GatewayUser (reflecting the inheritance relationship), and inserts two records into Student. All good. On fetching, the SELECT joins the two user tables, and I get a GatewayUser object, but accessing the Students collection does not trigger a SELECT on the Student table. But if I change the mapping to Lazy(CollectionLazy.NoLazy), the SQL to select eagerly load Students appears in the log, but the collection is not populated. If I switch the database from SQLite to Sql Server, I see the student records in the table. The generated SQL (when NoLazy is applied) will fetch them. So on the database end, things look fine.
I have to think my Frankenstein mapping situation is to blame. I'm mixing the library's conformist mapping with Fluent mapping, and there are two different base entity classes. However, the generated schema looks correct, and the save cascades correctly, so I don't know if that's the issue.
Found my own answer. My mapping of the parent class's list was like this:
public class GatewayUserMap : JoinedSubclassMapping
{
public GatewayUserMap()
{
Key(g => g.Column("Id"));
Property(c => c.FirstName, m => m.Length(50));
// ... more properties
List(gu => gu.Students, map =>
{
map.Key(c => c.Column("GatewayUser_Id"));
map.Cascade(Cascade.All | Cascade.DeleteOrphans);
map.Index(li => li.Column("ListIndex"));
map.Access(Accessor.Field | Accessor.NoSetter);
}
);
}
}
I have a private backing field for the collection. Removing Accessor.NoSetter from the collection mapping fixed it. In fact, it still worked without Accessor.Field -- I guess the mapper does a good job of looking around for one, and using it if found. Changing the name of the private backer from "_students" to "funnyName" prevented the mapper from finding it.

How to easily access widely different subsets of fields of related objects/DB tables?

Imagine we have a number of related objects (equivalently DB tables), for example:
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
}
public class Job {
private String company;
private int salary;
..
}
public class House {
private Address address;
private int age;
private int numRooms;
..
}
public class Address {
private String town;
private String street;
..
}
How to best design a system for easily defining and accessing widely varying subsets of data on these objects/tables? Design patterns, pros and cons, are very welcome. I'm using Java, but this is a more general problem.
For example, I want to easily say:
I'd like some object with (Person.name, Person.height, Job.company, Address.street)
I'd like some object with (Job.company, House.numRooms, Address.town)
Etc.
Other assumptions:
We can assume that we're always getting a known structure of objects on the input, e.g. a Person with its Job, House, and Address.
The resulting object doesn't necessarily need to know the names of the fields it was constructed from, i.e. for subset defined as (Person.name, Person.height, Job.company, Address.street) it can be the array of Objects {"Joe Doe", 180, "ACompany Inc.", "Main Street"}.
The object/table hierarchy is complex, so there are hundreds of data fields.
There may be hundreds of subsets that need to be defined.
A minority of fields to obtain may be computed from actual fields, e.g. I may want to get a person's age, computed as (now().getYear() - Person.birtday.getYear()).
Here are some options I see:
A SQL view for each subset.
Minuses:
They will be almost the same for similar subsets. This is OK just for field names, but not great for the joins part, which could ideally be refactored out to a common place.
Less testable than a solution in code.
Using a DTO assembler, e.g. http://www.genericdtoassembler.org/
This could be used to flatten the complex structure of input objects into a single DTO.
Minuses:
I'm not sure how I'd then proceed to easily define subsets of fields on this DTO. Perhaps if I could somehow set the ones irrelevant to the current subset to null? Not sure how.
Not sure if I can do computed fields easily in this way.
A custom mapper I came up with.
Relevant code:
// The enum has a value for each field in the Person objects hierarchy
// that we may be interested in.
public enum DataField {
PERSON_NAME(new PersonNameExtractor()),
..
PERSON_AGE(new PersonAgeExtractor()),
..
COMPANY(new CompanyExtractor()),
..
}
// This is the container for field-value pairs from a given instance of
// the object hierarchy.
public class Vector {
private Map<DataField, Object> fields;
..
}
// Extractors know how to get the value for a given DataField
// from the object hierarchy. There's one extractor per each field.
public interface Extractor<T> {
public T extract(Person person);
}
public class PersonNameExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getName();
}
}
public class PersonAgeExtractor implements Extractor<Integer> {
public int extract(Person person) {
return now().getYear() - person.getBirthday().getYear();
}
}
public class CompanyExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getJob().getCompany();
}
}
// Building the Vector using all the fields from the DataField enum
// and the extractors.
public class FullVectorBuilder {
public Vector buildVector(Person person) {
Vector vector = new Vector();
for (DataField field : DataField.values()) {
vector.addField(field, field.getExtractor().extract(person));
}
return vector;
}
}
// Definition of a subset of fields on the Vector.
public interface Selector {
public List<DataField> getFields();
}
public class SampleSubsetSelector implements Selector {
private List<DataField> fields = ImmutableList.of(PERSON_NAME, COMPANY);
...
}
// Finally, a builder for the subset Vector, choosing only
// fields pointed to by the selector.
public class SubsetVectorBuilder {
public Vector buildSubsetVector(Vector fullVector, Selector selector) {
Vector subsetVector = new Vector();
for (DataField field : selector.getFields()) {
subsetVector.addField(field, fullVector.getValue(field));
}
return subsetVector;
}
}
Minuses:
Need to create a tiny Extractor class for each of hundreds of data fields.
This is a custom solution that I came up with, seems to work and I like it, but I feel this problem must have been encountered and solved before, likely in a better way.. Has it?
Edit
Each object knows how to turn itself into a Map of fields, keyed on an enum of all fields.
E.g.
public enum DataField {
PERSON_NAME,
..
PERSON_AGE,
..
COMPANY,
..
}
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
public Map<DataField, Object> toMap() {
return ImmutableMap
.add(DataField.PERSON_NAME, name)
.add(DataField.BIRTHDAY, birthday)
.add(DataField.HEIGHT, height)
.add(DataField.AGE, now().getYear() - birthday.getYear())
.build();
}
}
Then, I could build a Vector combining all the Maps, and select subsets from it like in 3.
Minuses:
Enum name clashes, e.g. if Job has an Address and House has an Address, then I want to be able to specify a subset taking street name of both. But how do I then define the toMap() method in the Address class?
No obvious place to put code doing computed fields requiring data from more than one object, e.g. physical distance from Address of House to Address of Company.
Many thanks!
Over in-memory object mapping in the application, I would favor database processing of the data for better performance. Views, or more elaborate OLAP/datawarehouse tooling could do the trick. If the calculated fields remain basic, as in "age = now - birth", I see nothing wrong with having that logic in the DB.
On the code side, given the large number of DTOs you have to deal with, you could use classless dynamic (available in some JVM languages) or JSON objects. The idea is that when a data structure changes, you only need to modify the DB and the UI, saving you the cost of changing a whole bunch of classes in between.

Save to an ArrayList of a model object

I am using Play Framework 2.0.4 and in my model class one of the variables is an Array List<Long> datatype, declared here:
public List<Long> associateBooks = new ArrayList<Long>();
I have a view template that invokes a controller method with two Long values that represent the id's of two different objects of the same model type.
GET /addAssociate/:oID/:id controllers.Application.addAssociate(oID: Long, id: Long)
The controller method invoked:
public static Result addAssociate(Long oID, Long id) {
Book.addAssociate(oID, id);
return redirect(routes.Application.index());
}
I know the controller method is performing its action because I get redirected to the index page and I know it receives the values because the URL changes as expected.
The problem lies in the Book model method addAssociate shown below.
public static void addAssociate(Long oID, Long match) {
List<Book> allBooks = new ArrayList<Book>();
allBooks = find.all();
for(Book book: allBooks) {
if(book.id == oID) {
book.associateBooks.add(match);
book.save();
}
}
}
In this method I want to go through all book objects and if the id matches the value of the variable oID passed from the view to the controller I want to add the value of match (the other arguement) to the associateBooks list (of type Long) that belongs to each journey object. I then try and save the changes to the object being considered during this iteration. The problem is the list associateBooks still seems to be empty when I print it out on other view templates.
Update: Even if I remove the condition it still doesn't add anything to the list.
If you want to save your list of associated books, maybe you would like to follow this:
NOTE: I suggest to create additional table named book_associated. It look like this
+--------+-------------------+
|book_id |associated_book_id |
+--------+-------------------+
|1 |2 |
|1 |3 |
+--------+-------------------+
It means that book with ID 1 associated with book with ID 2 and 3
But, this has a disadvantages if Book 1 is associated with Book 2 we cannot determine if Book 2 is also associated with Book 1 because it didn't declared on the table.
So on your model should look like below:
#Entity
#Table(name = "book")
public class Book extends Model {
#Id
public Long id;
// other fields
...
#ManyToMany
#JoinTable(name="book_associated",
joinColumns=
#JoinColumn(name="book_id", referencedColumnName="id"),
inverseJoinColumns=
#JoinColumn(name="associated_book_id", referencedColumnName="id")
)
public List<Book> associateBooks = new ArrayList<>();
// other methods and finder
...
}
Here you can save all your list of associated book of any book. This is for your reference about Many-to-Many relation on java :
http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany
http://www.objectdb.com/api/java/jpa/ManyToMany

Hibernate: Adding a new element to association list does not persist

I have a ManyToMany association between two Entities: COURSE and STUDENT. They are associated through a STUDENT_COURSE_MAP association table.
Course.java:
#Entity
#Table(name="COURSE")
public class Course implements java.io.Serializable {
#ManyToMany(
mappedBy="courses",
cascade={CascadeType.PERSIST, CascadeType.MERGE}
)
private List<Student> students = Collections.emptyList();
// Rest of the class, getters, setters etc
}
Student.java:
#Entity
#Table(name="STUDENT")
public class Student implements java.io.Serializable {
#ManyToMany(
targetEntity=Course.class,
cascade = { CascadeType.PERSIST, CascadeType.MERGE }
)
#JoinTable(
name="STUDENT_COURSE_MAP",
joinColumns=#JoinColumn(name="STUDENT_REF"),
inverseJoinColumns=#JoinColumn(name="COURSE_REF")
)
private Set<Course> courses = Collections.emptySet();
// Rest of the class, getters, setters etc
}
I want to add a student (id=11) list for one particular course (id=77) as follows (transaction is already begun):
// Create new list and add a student to it
Student student_11 = (Student) session.get(Student.class.getName(), 11);
List<Student> studentsList = new ArrayList<Student>(1);
studentsList.add(student_11);
// Now, set the list of students in the course
Course course_77 = (Course) session.get(Course.class.getName(), 77);
course_77.setStudents(studentsList);
I save it using the following code:
session.flush();
session.getTransaction().commit();
However, the association - course_77 and student_11 - does not get persisted to the database. There are no insert statements generated in the hibernate log.
I even tried calling session.saveOrUpdate(course_77). Only the following is logged when saveOrUpdate is called:
allowing proxied method [saveOrUpdate] to proceed to real session
persistent instance of: org.whatra.tradecog.db.entity.Artist
ignoring persistent instance
object already associated with session: [Course#77]
Hints/tips/solutions are much appreciated.
Note 1:
The whole persistence thing works just fine for me when I create new Course and Student objects and save. What does not work is when I retrieve existing Course and existing Student objects and add a new association between them.
Here's what was wrong. It turns out I was saving only one side of the association. This is what I should have done:
// Create new list and add a student to it
Student student_11 = (Student)session.get(Student.class.getName(), 11);
Course course_77 = (Course) session.get(Course.class.getName(), 77);
List studentsList = new ArrayList(1);
studentsList.add(student_11);
Set coursesList = new HashSet(1);
coursesList.add(course_77);
course_77.setStudents(studentsList);
// THIS IS WHAT'S WRONG - I MISSED THIS NEXT LINE
student_11.setCourses(coursesList);
I found the answer at http://en.wikibooks.org/wiki/Java_Persistence/Relationships (look under 'Common Problems').