Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/JPA/MappingSelectionCriteria"

m (Example of Expression criteria relationship)
m
 
(7 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Normally in the database a relationship is defined through a foreign key, either from the source table to the target table (ManyToOne), or from the target table to the source table (OneToMany).  However, sometimes a relationship is more complex, and involves a comparison or computation.  The JPA specification only allows relationships to be defines using foreign keys (JoinColumn), but EclipseLink also provides and extended Expression criteria API to allow complex relationships to be defined.
+
[[Category:EclipseLink/Example/JPA|MappingSelectionCriteria]]
 +
{{EclipseLink_DocWiki
 +
|link=http:EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Relationship_Mappings/Collection_Mappings}}
 +
 
 +
=Mapping Selection Criteria=
 +
 
 +
Normally in the database a relationship is defined through a foreign key, either from the source table to the target table (ManyToOne), or from the target table to the source table (OneToMany).  However, sometimes a relationship is more complex, and involves a comparison or computation.  The JPA specification only allows relationships to be defines using foreign keys (JoinColumn), but EclipseLink also provides an extended Expression criteria API to allow complex relationships to be defined.
 +
 
 +
__TOC__
 +
 
 +
== Example 1: Department.manager (1:1) ==
  
 
Consider a Department that has a "manager" relationship to Employee.  Instead of having a foreign key to its manager, the Employee has a foreign key to its Department, and an additional field that defines the Employee's position.  EclipseLink does not currently define an annotation to define an Expression relationship so a DescriptorCustomizer can be used.
 
Consider a Department that has a "manager" relationship to Employee.  Instead of having a foreign key to its manager, the Employee has a foreign key to its Department, and an additional field that defines the Employee's position.  EclipseLink does not currently define an annotation to define an Expression relationship so a DescriptorCustomizer can be used.
  
===Example of Expression criteria relationship===
 
 
<source lang="java">
 
<source lang="java">
 
@Entity
 
@Entity
Line 34: Line 43:
  
 
public class DepartmentCustomizer implements DescriptorCustomizer {
 
public class DepartmentCustomizer implements DescriptorCustomizer {
     public void customizer(ClassDescriptor descriptor) {
+
 
 +
     public void customize(ClassDescriptor descriptor) {
 
         OneToOneMapping mapping = (OneToOneMapping)descriptor.getMappingForAttributeName("manager");
 
         OneToOneMapping mapping = (OneToOneMapping)descriptor.getMappingForAttributeName("manager");
 
         ExpressionBuilder builder = new ExpressionBuilder();
 
         ExpressionBuilder builder = new ExpressionBuilder();
 
         mapping.setSelectionCriteria(builder.getField("EMPLOYEE.DEPT_ID").equal(builder.getParameter("DEPARTMENT.DEPT_ID").
 
         mapping.setSelectionCriteria(builder.getField("EMPLOYEE.DEPT_ID").equal(builder.getParameter("DEPARTMENT.DEPT_ID").
        and(builder.getField("EMPLOYEE.POSITION").equal("MANAGER"));
+
            and(builder.getField("EMPLOYEE.POSITION").equal("MANAGER"));
 
     }
 
     }
 +
 +
}
 +
</source>
 +
 +
== Example 2: 'active == true' in 1:M ==
 +
 +
=== Domain Model ===
 +
 +
<source lang="java">
 +
@Entity
 +
@Table(name = "FILT_A")
 +
@Customizer(ConfigureBsFilter.class)
 +
public class A implements Serializable {
 +
 +
@Id
 +
@Column(name = "A_ID")
 +
private int id;
 +
 +
/**
 +
* Collection of Active B's. The application is responsible for ensuring
 +
* that when committing a TXN that no inactive B instances exist in the list
 +
*/
 +
@OneToMany(mappedBy="a", cascade=CascadeType.ALL)
 +
private List<B> bs;
 +
 +
</source>
 +
 +
<source lang="java">
 +
@Entity
 +
@Table(name = "FILT_B")
 +
public class B {
 +
 +
@Id
 +
@Column(name = "B_ID")
 +
private int id;
 +
 +
@ManyToOne(fetch = FetchType.LAZY)
 +
@JoinColumn(name = "A_ID")
 +
private A a;
 +
 +
private boolean active;
 +
 +
private String value;
 +
</source>
 +
 +
=== Customize A.Bs Criteria ===
 +
 +
<source lang="java">
 +
public class ConfigureBsFilter implements DescriptorCustomizer {
 +
 +
public void customize(ClassDescriptor descriptor) throws Exception {
 +
OneToManyMapping mapping = (OneToManyMapping) descriptor
 +
.getMappingForAttributeName("bs");
 +
 +
ExpressionBuilder eb = new ExpressionBuilder(mapping
 +
.getReferenceClass());
 +
Expression fkExp = eb.getField("A_ID").equal(eb.getParameter("A_ID"));
 +
Expression activeExp = eb.get("active").equal(true);
 +
 +
mapping.setSelectionCriteria(fkExp.and(activeExp));
 +
}
 
}
 
}
 
</source>
 
</source>

Latest revision as of 11:53, 8 February 2011

Mapping Selection Criteria

Normally in the database a relationship is defined through a foreign key, either from the source table to the target table (ManyToOne), or from the target table to the source table (OneToMany). However, sometimes a relationship is more complex, and involves a comparison or computation. The JPA specification only allows relationships to be defines using foreign keys (JoinColumn), but EclipseLink also provides an extended Expression criteria API to allow complex relationships to be defined.

Example 1: Department.manager (1:1)

Consider a Department that has a "manager" relationship to Employee. Instead of having a foreign key to its manager, the Employee has a foreign key to its Department, and an additional field that defines the Employee's position. EclipseLink does not currently define an annotation to define an Expression relationship so a DescriptorCustomizer can be used.

@Entity
@Customizer(org.acme.persistence.DepartmentCustomizer.class)
public class Department {
    @Id
    private long id;
    @OneToOne
    private Employee manager;
    @OneToMany(mappedBy="department")
    private List<Employee> employees;
    ...
}
@Entity
public class Employee {
    @Id
    private long id;
    @ManyToOne
    @JoinColumn(name="DEPT_ID")
    private Department department;
}
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.mappings.OneToOneMapping;
 
public class DepartmentCustomizer implements DescriptorCustomizer {
 
    public void customize(ClassDescriptor descriptor) {
        OneToOneMapping mapping = (OneToOneMapping)descriptor.getMappingForAttributeName("manager");
        ExpressionBuilder builder = new ExpressionBuilder();
        mapping.setSelectionCriteria(builder.getField("EMPLOYEE.DEPT_ID").equal(builder.getParameter("DEPARTMENT.DEPT_ID").
            and(builder.getField("EMPLOYEE.POSITION").equal("MANAGER"));
    }
 
}

Example 2: 'active == true' in 1:M

Domain Model

@Entity
@Table(name = "FILT_A")
@Customizer(ConfigureBsFilter.class)
public class A implements Serializable {
 
	@Id
	@Column(name = "A_ID")
	private int id;
 
	/**
	 * Collection of Active B's. The application is responsible for ensuring
	 * that when committing a TXN that no inactive B instances exist in the list
	 */
	@OneToMany(mappedBy="a", cascade=CascadeType.ALL)
	private List<B> bs;
@Entity
@Table(name = "FILT_B")
public class B {
 
	@Id
	@Column(name = "B_ID")
	private int id;
 
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "A_ID")
	private A a;
 
	private boolean active;
 
	private String value;

Customize A.Bs Criteria

public class ConfigureBsFilter implements DescriptorCustomizer {
 
	public void customize(ClassDescriptor descriptor) throws Exception {
		OneToManyMapping mapping = (OneToManyMapping) descriptor
				.getMappingForAttributeName("bs");
 
		ExpressionBuilder eb = new ExpressionBuilder(mapping
				.getReferenceClass());
		Expression fkExp = eb.getField("A_ID").equal(eb.getParameter("A_ID"));
		Expression activeExp = eb.get("active").equal(true);
 
		mapping.setSelectionCriteria(fkExp.and(activeExp));
	}
}