Mapping Extra Attribute in a Join Table JPA 2 - jpa-2.0

I am trying to model this relationship following this link http://www.javaworld.com/javaworld/jw-01-2008/images/datamodel.gif
Its the usual Many to Many relationship between Order and Products but I dont know how to add the extra columns in the Join table.
#Entity
#Table(name = "Orders")
public class Order {
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "ORDER_LINES", joinColumns = { #JoinColumn(name = "ORDER_ID") }, inverseJoinColumns = { #JoinColumn(name = "PROD_ID") })
private Set<Product> products;
}
#Entity
#Table(name="PRODUCTS")
public class Product {
#ManyToMany(mappedBy="products")
private Set<Order> orders;
}
How to add Join Table extra attribute in JPA 2.0?
Thanks

There is no concept of having additional persistent attribute in relation in JPA (2.0). That's why relation with property is actually intermediate entity.
From both Order and Product entities, you need one-to-many relationship to new entity. Because of bidirectional relationship, new entity will have many-to-one relationships to Order and Product.
You need to go for something like this (shows only relationships, id's and other mappings stripped away):
#Entity
#Table(name="order_item")
public class OrderItem {
#ManyToOne
private Order order;
#ManyToOne
private Product product;
}
#Entity
public class Order {
#OneToMany (mappedBy = "order")
private Set<OrderItem> orderItems;
}
#Entity
public class Product {
#OneToMany(mappedBy = "product")
private Set<OrderItem> orderItems;
}

Related

Getting Relationship properties using spring data neo4j node repository

If we have a Company Node like this which is linked to another Node (Location) using OWNS relationship.
#NodeEntity ("Company")
public class Company {
#Id
#Property
private String companyId;
#Property
private String partyId;
#Relationship (type = "OWNS", direction = Relationship . OUTGOING )
private Set<Location> ownedLocations;
}
OWNS relationship
#RelationshipEntity (type = "OWNS")
public class Owns {
#Property
private String ownsProperty;
#StartNode
private Company company;
#EndNode
private Location location;
}
Here is the Repository
#Repository
public interface CompanyRepository extends Neo4jRepository<Company, String> {
#Query ("match (c:Company)-[x:OWNS]-(y) where c.partyId = $0 return c,x,y")
Stream<Company> getCompaniesWithRelationsByPartyId(final String partyId);
}
So when i run this query i am getting only Company and Location entities but no OWNS ownsProperty. How to get relationship properties using above repository?
NOTE: I don't want to use #QueryResult
enter code here
You have to define the Owns relationship entity as the type for the relationship in the Company like this
#Relationship (type = "OWNS", direction = Relationship . OUTGOING )
private Set<Owns> ownedLocations;

Designing Model with foreign key

I am building an ORM by using Unit or Work and Repository using Dapper. I have searched the internet on this problem and no luck.
I have the following tables:
As you can see, Instance has Entity inside. I have 2 approaches:
Approach 1:
public class Entity
{
public int Id {get;set;}
public string Name {get;set;}
}
public class Instance
{
public int Id {get;set;}
public Entity Entity {get;set;}
public string Name {get;set;}
}
How can I get value for Entity with this approach?
Approach 2 (according to this link):
public class Entity
{
public int Id {get;set;}
public string Name {get;set;}
}
public class Instance
{
public int Id {get;set;}
public int EntityId {get;set;}
public string Name {get;set;}
}
Which design is better for use?
You can use QueryMultiple if you want to fetch the data from two different tables and fill it up in two different POCO classes. Following is copied from here:
string sql = "SELECT * FROM Invoice WHERE InvoiceID = #InvoiceID; SELECT * FROM InvoiceItem WHERE InvoiceID = #InvoiceID;";
using (var connection = My.ConnectionFactory())
{
connection.Open();
using (var multi = connection.QueryMultiple(sql, new {InvoiceID = 1}))
{
var invoice = multi.Read<Invoice>().First();
var invoiceItems = multi.Read<InvoiceItem>().ToList();
}
}
Both the models you mentioned in your code can be handled with this approach.
As an alternative approach, you can combine your two POCOs in one or you can use inheritance as well. But, looking at your data model, I do not think this is applicable to this particular case.
Which design is better for use?
Up to you. Whatever suits your project needs keeping down the unnecessary complexities is good for you.

JPA OneToOne bi-directional

I have two entities and they are related to each other through a one to one relationship. User is the owner of Balance. I set Hibernate to automatically create tables and this does not seem to be working. The problem may be caused by other causes but I'd like to make sure that I have the one to one relationship configured correctly first.
Can you please check the following entities and tell me if they are correct?
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne
#JoinColumn(name = "balance_id", referencedColumnName = "id")
private Balance balance;
}
#Entity
#Table(name = "balances")
public class Balance implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne(mappedBy = "users")
private User user;
}
No, it's not correct. The value of mappedBy must be the name of the attribute, in the other entity, which is the owner side of the association:
#OneToOne(mappedBy = "balance")

how to create query in Criteria api

I have a class:
#Entity
public class Resume {
private Long id;
#Embedded
private DesiredPositionAndSalary desiredPositionAndSalary;
}
and class:
#Embeddable
public class DesiredPositionAndSalary {
#ManyToMany
private Set<Specialization> specializations;
}
and class ;)
#Entity
public class Specialization {
private Long id;
}
now i have some Specializations that i need filtered by.
For example i need to select all resume with one of specialization like programmer or manager. Something like
select * from resume r inner join resume_to_specialization rts on r.id = rts.id inner join specialization s on rts.spec_id in(1,2)
how can i write this query in Criteria api? If i miss some major details i can give more.
Ok, i handle it with this:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Resume> cq =cb.createQuery(Resume.class);
Root<Resume> root = cq.from(Resume.class);
cq.select(root);
Set<Specialization> filter = getFilter();
SetJoin<DesiredPositionAndSalary, Specialization> join = root.join(Resume_.desiredPositionAndSalary, JoinType.INNER).join(
DesiredPositionAndSalary_.specializations, JoinType.INNER);
cq.where(cb.and(cq.getRestriction(), join.in(filter)));
cq.distinct(true);/*it is major, or we get duplicate of resume for every
specialization overlap with filter*/
List<Resume> result = em.createQuery(cq).getResultList();
.

JPA2 Criteria queries on entity hierarchy

suppose i have the following entity domain:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
public abstract class Entity1 {
//some attributes
}
#Entity
#DiscriminatorValue("T1")
public class Entity2 extends Entity1 {
#OneToMany(fetch=FetchType.EAGER, cascade = { CascadeType.ALL }, mappedBy="parent")
#Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Entity1Detail> details = new HashSet<Entity1Detail>();
}
#Entity
public class Entity1Detail {
#ManyToOne
#JoinColumn(name="REF")
private Entity2 parent;
#Basic
private Integer quantity;
}
#Entity
#DiscriminatorValue("T2")
public class Entity3 extends Entity1 {
//some other attributes
}
when i do a JPQL query:
select e from Entity1 e left join e.details d where d.quantity > 1
it runs well (left join ;P). however when i try to construct the same query using JPA2 Criteria API:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery q = builder.createQuery();
Root r = q.from(Entity1.class);
q.select(r);
q.where(builder.gt(r.join("details", JoinType.LEFT).get("quantity"), 1));
i get NPE in "join" because the attribute "details" doesn't belong to Entity1 (which is actually true, i have to select on Entity2.class instead). the thing is that when i have to construct my dynamic query using Criteria API i don't really know anything about hierarchy, i'm just passed a Class.
i understand that Criteria API is typesafe and all that, but is there a way to work around this? with aliases maybe (as before i used Hibernate Criteria API, traversing joins with aliases):
Criteria c = session.createCriteria(Entity1.class);
c.createAlias("details", "d");
c.add(Restrictions.ge("d.quantity", 1));
You need to base your query on entity2.details. Since the criteria API is type-safe, it catches that entity1 has no field named "details"
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery q = builder.createQuery();
Root r = q.from(Entity2.class); // Must use subclass as root
q.select(r);
q.where(builder.gt(r.join("details", JoinType.LEFT).get("quantity"), 1));
Since Entity2 extends Entity1, you can cast your results as the parent type safely. For example:
CriteriaQuery<Entity1> q = builder.createQuery(Entity1.class);
Root r = q.from(Entity2.class); // Must use subclass as root
will return a list of Entity1
CriteriaQuery<Entity2> q = builder.createQuery(Entity2.class);
Root r = q.from(Entity2.class); // Must use subclass as root
will return a list of Entity2
EDIT:
I think I misunderstood the goal here. If you want all Entity1 UNLESS they are Entity2 with details.quantity <= 1, you need to do more.
You can't use a left join from Entity1Detail to Entity1, because that is not strictly type safe. Instead, you need to join Entity2 to Entity1Detail somehow. Probably the best tool to use here is a correlated subquery.
CriteriaQuery<Entity1> q = builder.createQuery(Entity1.class);
Root<Entity1> ent1 = q.from(Entity1.class);
SubQuery<Entity2> subq = q.subquery(Entity2.class);
Root<Entity2> ent2 = subq.from(Entity2.class);
Path<Integer> quantity = ent2.join("details", JoinType.LEFT).get("quantity");
Predicate lessThan = builder.lte(quantity,1);
Predicate correlatedSubqJoin = cb.equal(ent1,ent2)
subq.where(lessThan, correlatedSubqJoin);
q.select(ent1);
q.where(builder.exists(subq).not());
The criteria API does not know that you are single table inheritance, so you have to write your queries for all inheritance strategies, including a Joined inheritance strategy.