Good evening everybody, this is my first post on Stack Overflow.
I have been quite recently introduced to Java 6 EE and, in particular, to JPA as part of the JSF 2.1 framework and I am now facing a strange behavior that I would like you to help me understand.
In our project (developed using NetBeans 7.2) we have several one-to-many relationship and we would like to navigate them the same way we navigate many-to-one ones. The fact is that, instead, we are able to make them work as we want only after having restarted the application server (Glassfish 3.1.2) and, in addition, this behavior lasts only till the next deployment; which means we need to restart Glassfish every time we apply a modification...
Here are some code excerpts to help you understand our situation.
This represents our main entity (Person) that has, among the others, a one-to-many relationship with Email as well as with Phone and a many-to-one relationship with AccountType
#Entity
public class Person implements Serializable {
//
//private non-collection fields including id
//
#OneToMany(mappedBy="person", fetch=FetchType.EAGER)
private Collection<Email> personEmails;
#OneToMany(mappedBy="person")
private Collection<Phone> personPhones;
#ManyToOne
private AccountType accountType;
//
// getter and setter, hashCode, isEqual and toString
//
}
And these are Email...
#Entity
public class Email implements Serializable {
//
//private non-collection fields including id
//
private String address;
#ManyToOne
private Person person;
//
// getter and setter, hashCode, isEqual and toString
//
}
... Phone ...
#Entity
public class Phone implements Serializable {
//
//private non-collection fields including id
//
private String number;
#ManyToOne
private Person person;
//
// getter and setter, hashCode, isEqual and toString
//
}
... and AccountType
#Entity
public class AccounType implements Serializable {
//
//private non-collection fields including id
//
private String name;
#OneToMany(mappedBy="accountType")
private Collection<Person> persons;
//
// getter and setter, hashCode, isEqual and toString
//
}
We have then set up a sample page to test how that three fields in Person are actually fetched.
This represents the xhtml page...
<h:form id="form">
<h:panelGrid columns="2">
<h:outputLabel value="forename" />
<h:outputLabel value="#{meBean.currentUser.forename}" />
<h:outputLabel value="emails" />
<h:outputLabel value="#{meBean.currentUser.personEmails.size()}" />
<h:outputLabel value="phones" />
<h:outputLabel value="#{meBean.currentUser.personPhones}" />
<h:outputLabel value="accountType" />
<h:outputLabel value="#{meBean.currentUser.accountType.name}" />
</h:panelGrid>
</h:form>
... and this the controller
#ManagedBean
#RequestScoped
public class MeBean {
#EJB
private PersonFacade personFacade;
private Person currentUser;
public MeBean() {
init();
}
#PostConstruct
private void init() {
// Hard-coding user details
try {
this.currentUser = this.personFacade.getFromUsername("user1");
this.currentUser.getPersonPhones().isEmpty();
} catch (Exception e) {
}
}
public Person getCurrentUser() {
return currentUser;
}
public void setCurrentUser(Person currentUser) {
this.currentUser = currentUser;
}
}
Now, the result we get is the one we expect only if we access the page right after having restarted the application server.
forename Alice
emails 2
phones {[sums.groupa.entities.Phone[id=38]]}
accountType Student
If we modify anything (except for the view) and save, after the inevitable deploy, the result is different.
forename Alice
emails 0
phones {[]}
accountType Student
Why is that happening and how can we avoid it?
Thanks in advance.
AG
A couple of contributors (that I want to thank for their quick replies) asked for the PersonFacade implementation.
public Person getFromUsername(String username)
{
try
{
Query q = em.createQuery("SELECT p FROM Person p LEFT JOIN FETCH p.personEmails WHERE UPPER(p.username) = :username");
q.setParameter("username", username.toUpperCase());
return (Person) q.getSingleResult();
}
catch (Exception ex)
{
Logger.getLogger(PersonFacade.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
As you can see I tried to use FETCH JOIN as suggested but the query is getting out too many results: it should fetch only one instance of Person representing Alice and containing two instances of Email in the personEmails field but I suspect it is getting two different instances of Person, each having a different instance of Email attached.
The original query was as follows:
SELECT p FROM Person p WHERE UPPER(p.username) = :username
Thanks again.
AG
I don't know how you wrote your personFacade and got the Person entity.
But I guess you used query.
If you are using JPQL, try fetch join.
Related
I have a database table displayed through Datatable (Primefaces 3.4.2) and I want to show a comboFilter in the header populated with values from the database table itself.
1) Since these values are not a PK or FK, I built a named query to retrieve distinct values for the prefDep column:
#NamedQuery(name = "Upb.findPrefDeps", query = "SELECT DISTINCT u FROM Upb u WHERE u.prefDep = :prefDep")
2) In my AbstractController:
public List<T> getPrefDepsList() {
if (prefDeps == null) {
prefDeps = this.ejbFacade.findPrefDeps();
}
return prefDeps;
}
3) As I inject the facade EJB, how can I build a managed bean property to be used in the filterOption below?
The managedBean:
#ManagedBean(name = "upbController")
#ViewScoped
public class UpbController extends AbstractController<Upb> implements Serializable {
#EJB
private UpbFacade ejbFacade;
public UpbController() {
super(Upb.class);
}
#PostConstruct
public void init() {
super.setFacade(ejbFacade);
}
public SelectItem[] getPrefDepOptions() {
return prefDepOptions; //build/populate this
}
}
The jsf:
<p:column filterBy="prefdep" headerText="PrefDep"
filterOptions="#{upbController.prefDepOptions}"
filterMatchMode="exact">
<h:outputText value="#{item.prefDep}" />
</p:column>
Thanks in advance.
I do not know if I understand your question the right way. You want to execute the named query once and store the distinct values in a property in the managed bean? For that you can use a PreRenderView event which would be called before rendering the page. You can call a init-function to load such values with this event.
You can also access the getter with the named query, but this may be called not only once.
I am new to using Play! Framework 2.X and have a simple question.
How can i send to my method Job.create(filledJob) a fully set Job object? Meaning that Company object including in Job object is filled too.
I have the following:
public class Job {
public String title;
public Company company;
}
public class Company {
public String name;
public String email;
}
I have a form in my template, containing a Job information section and a Company section
#(jobForm: Form[Job], companyForm: Form[Company])
#form(routes.Application.newJob()) {
#inputText(jobForm("title"))
#inputText(companyForm("name"))
<input type="submit" value="Create">
}
My controller(Application.java) looks like that:
public class Application extends Controller {
static Form<Job> jobForm = form(Job.class);
static Form<Company> companyForm = form(Company.class);
public static Result index() {
return ok(
views.html.index.render(jobForm, companyForm)
);
}
public static Result newJob() {
Form<Job> filledForm = jobForm.bindFromRequest();
Job.create(filledForm.get());
return redirect(routes.Application.index());
}
}
Ideally, i would like to send to my method Job.create(job), with job with all the fields set (string job title as well as Company object). It must be a numpty question, i appologize for that. Any help would be greatly appreciated
Many thanks
You can't use #inputText(companyForm("name")) if you want bind the form directly into object, but instead you can use a select form helper for selecting the company, check ie. computer-database sample it's quite similar case...
On the other hand if you have a lot of companies and don't want to create huge select consider another scenario: just instead route like /job/new use /company/:companyId/add-job in other words just you'll send a form and bind it from request + additionaly will get Company by id in route param and will add to object, pseudo code:
public static Result addJobToCompany(Integer companyId){
Job job = form(Job.class).bindFromRequest().get();
job.company = Company.find.byId(companyId);
job.save();
return redirect(routes.Application.jobDetails(job.id));
}
Ok i am replying to my own question as i must not have explained my question clearly.
To make it simple : I needed to set the Company object from a form. Find below my solution
Hope it will help you.
public class Job {
public String title;
#Valid
public Company company;
}
public class Company {
public String name;
public String email;
}
#(jobForm: Form[Job], companyForm: Form[Company])
#form(routes.Application.newJob()) {
#inputText(jobForm("title"))
#inputText(jobForm("company.name"))
<input type="submit" value="Create">
}
Say I have two domain objects and a mapper interface.
class Person {
int id;
List<Problem> problems = new ArrayList<Problem>();
}
class Problem {
int id;
Person person;
}
interface PersonMapper {
public List<Person> selectAllPersons();
}
And two database tables.
create table person (
id integer not null generated always as identity constraint person_pk primary key,
)
create table problem (
id integer not null generated always as identity constraint problem_pk primary key,
person_id integer not null constraint problem_person_fk references person
)
I can create a mapping file that gets the data I want.
<resultMap id="personMap" type="Person">
<id column="person_id" property="id" />
<collection column="problem_person_id" property="problems"
javaType="ArrayList" ofType="Problem" resultMap="problemMap" />
</resultMap>
<resultMap id="problemMap" type="Problem">
<id column="problem_id" property="id" />
<!-- Adding an association here will cause a circular dependency -->
<!-- The circular dependency results in a StackOverflowException -->
</resultMap>
<select id="selectAllPersons" resultMap="personMap">
select
person.id as person_id,
problem.id as problem_id
from person left outer join problem on person.id = problem.person_id
</select>
However, since MyBatis doesn't do bi-directional mapping, none of the Problem objects in the returned collections will have their Person reference set correctly.
According to this issue, it sounds like I should be able to update my mapper interface and add a custom result handler that can be supplied by the calling class.
interface PersonMapper {
public List<Person> selectAllPersons(ResultHandler handler);
}
class PersonResultHandler implements ResultHandler {
#Override
public void handleResult(ResultContext context) {
System.out.println(context.getResultObject());
}
}
class PersonDAO {
// Get SqlSession sqlSession
sqlSession.getMapper(PersonMapper.class).selectAllPersons(new PersonResultHandler());
}
However, the handleResult method of my ResultHandler never gets called. I've seen this example, but the extra fluff class in there makes it very difficult to understand. Can anyone give me a simple example of using a custom ResultHandler with mapper interfaces? I'm using MyBatis 3.0.5+.
I've also read through the MyBatis mailing list and there are several suggestions of using caching and lazy loading to solve circular dependencies, but I can't find any examples of how to do it.
You should replace your method declaration to:
interface PersonMapper {
public void selectAllPersons(ResultHandler handler);
}
And populate List<Person> inside your PersonResultHandler
class PersonResultHandler implements ResultHandler {
List<Person> persons = new ArrayList<Person>();
#Override
public void handleResult(ResultContext context) {
Object result = context.getResultObject();
if (result instanceof Person) {
Person person = (Person) result;
for (Problem problem : person.getProblems()) {
problem.setPerson(person);
}
persons.add(person);
}
}
public List<Person> getPersons() {
return persons;
}
}
Here's a simple example of a problem I'm running across that is not meshing with some of the ideas presented here and other places regarding DDD.
Say I have an ASP.NET MVC 3 site that creates/manipulates a person. The controllers access an application service layer (PersonService) which in turn uses the domain entities (EF 4 POCO) and the PersonRepository to make changes and persist them. I'm leaving out all interfaces here for simplicity. Person is the root in this case and for simplicity only has email addresses (also assume email is not immutable and can be updated).
Option 1:
Try to stick with [my understanding] of the basics of DDD where behavior directly related to the entity is implemented as part of the entity (Person implements AddEmail, ChangeEmail, etc). The only problem with this, with the exception of the Add* methods, is that the Person would need to know about the context or entity framework pieces (which would remove any persistence ignorance) or need to use a "service" or repository to mark the email as modified.
// Person Service
public class PersonService {
// constructor injection to get unit of work and person repository...
// ...methods to add/update a person
public EmailAddress AddEmailAddress(int personId, EmailAddress email)
{
Person p = personRepository.Find(p => p.Id == personId).First();
p.AddEmail(email);
uow.SaveChanges();
return email;
}
public EmailAddress ChangeEmailAddress(EmailAddress email)
{
Person p = personRepository.Find(p => p.Id == personId).First();
p.ChangeEmail(email);
// change state of email object here so it's updated in the next line???
// if not here, wouldn't the Person entity have to know about the context
// or use a service?
uow.SaveChanges();
return email;
}
}
// Person Repository
public class PersonRepository
{
// generic repository implementation
}
// Person Entity
public class Person
{
public string Name { get;set; }
public IEnumerable<EmailAddress> EmailAddresses { get;set; }
public void AddEmail(EmailAddress email)
{
this.EmailAddresses.Add(email);
}
public void ChangeEmail(EmailAddress email)
{
EmailAddress orig = this.EmailAddresses.First(e => e.Id == email.id);
// update properties on orig
// NOW WHAT? [this] knows nothing about the context in order to change state,
etc, or do anything to mark the email add updated
}
}
// Email
public class EmailAddress
{
public string Email { get;set; }
public bool IsPrimary { get;set; }
}
Option 2:
Let the person service use the repository to add/update the email address and don't implement the behavior on the person entity. This is much simpler in the case of many to many relationships (for example, address, where two tables need to be updated to complete the work) but the model then becomes 'anemic' being just a bunch of getters and setters.
// Person Service
public class PersonService {
// constructor injection to get unit of work and person repository...
// ...methods to add/update a person
public EmailAddress AddEmailAddress(int personId, EmailAddress email)
{
Person p = personRepository.Find(p => p.Id == personId).First();
personRepository.AddEmail(personId, email);
uow.SaveChanges();
return email;
}
public EmailAddress ChangeEmailAddress(EmailAddress email)
{
personRepository.ChangeEmail(email);
uow.SaveChanges();
return email;
}
}
// Person Repository
public class PersonRepository
{
// generic repository implementation
}
// Person Entity
public class Person
{
public string Name { get;set; }
public IEnumerable<EmailAddress> EmailAddresses { get;set; }
}
// Email
public class EmailAddress
{
public string Email { get;set; }
public bool IsPrimary { get;set; }
}
Anyway, any thoughts on this?
Thanks, Brian
Option 1 is the way to go.
Reasoning is simple - changing e-mail addresses is domain concern. I bet Your domain experts have said that they will need to change emails. That automatically marks email changing piece of logic as business logic which is supposed to live in domain model. Objects primarily are defined by their behavior and not data that they hold.
Also - think twice before You choose to use unit of work pattern and wrap around everything in services. Aggregate roots are supposed to draw transaction boundaries and services usually are useless if they just wrap repository and domain object calls.
I would have something like this:
public class Person{
public Email Email{get;private set;}
public void SpecifyEmail(Email email){
//some validation, if necessary
EnsureEmailCanBeChanged();
//applying state changes
Email=email;
//raising event, if necessary
Raise(new EmailChanged(this));
}
public class EmailChanged:Event<Person>{
public EmailChanged(Person p):base(p){}
}
}
public class Email{
public Email(string email){
//validations (e.g. email format)
Value=email;
}
//implicit to string, explicit from string conversions
}
public class PersonController{
public ActionResult SpecifyEmail(int person, string email){
_persons.Get(person).SpecifyEmail((Email)email);
return RedirectToAction("Person",new{person});
}
}
I'm using NHibernate - it's smart enough to figure out what has changed since Person was persisted last time. Hard to say how exactly entity framework handles this.
I'm an NH user and may not know all EF limitations but generally speaking, whatever the limitations of ORM, entities should be left as clean as possible. Service Layer is already coupled with Data Access so no harm's done.
And I believe EF4 should know how to track collection changes. If not, then the best way is to leave the adding/removing logic in your Person entity and persist in PersonService.
BTW, your EmailAddress isn't an entity here, no Id (just a typo I guess). And how do you link your EmailAddress to Person?
We have the simplest CRUD task with JPA 1.0 and JAX-WS.
Let's say we have an entity Person.
#Entity
public class Person
{
#Id
private String email;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(insertable = false, updatable = false)
private ReadOnly readOnly;
#Column
private String name;
#XmlElement
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
#XmlElement
public Long getReadOnlyValue()
{
return readOnly.getValue();
}
// more get and set methods
}
Here is scenario.
Client make Web Service request to create person. On the server side everything is straightforward.
And it does work as expected.
#Stateless
#WebService
public class PersonService
{
#PersistenceContext(name = "unit-name")
private EntityManager entityManager;
public Person create(Person person)
{
entityManager.persist(person);
return person;
}
}
Now client tries to update person and this is where, as for me, JPA shows its inconsistence.
public Person update(Person person)
{
Person existingPerson = entityManager.find(Person.class, person.getEmail());
// some logic with existingPerson
// ...
// At this point existingPerson.readOnly is not null and it can't be null
// due to the database.
// The field is not updatable.
// Person object has readOnly field equal to null as it was not passed
// via SOAP request.
// And now we do merge.
entityManager.merge(person);
// At this point existingPerson.getReadOnlyValue()
// will throw NullPointerException.
// And it throws during marshalling.
// It is because now existingPerson.readOnly == person.readOnly and thus null.
// But it won't affect database anyhow because of (updatable = false)
return existingPerson;
}
To avoid this problem I need to expose set for readOnly object and do something like this before merge.
Person existingPerson = entityManager.find(Person.class, person.getEmail());
person.setReadOnlyObject(existingPerson.getReadOnlyObject()); // Arghhh!
My questions:
Is it a feature or just
inconsistence?
How do you (or would
you) handle such situations? Please
don't advice me to use DTOs.
Is it a feature or just inconsistence?
I don't know but I'd say that this is the expected behavior with merge. Here is what is happening when calling merge on a entity:
the existing entity gets loaded in the persistence context (if not already there)
the state is copied from object to merge to the loaded entity
the changes made to the loaded entity are saved to the database upon flush
the loaded entity is returned
This works fine with simple case but doesn't if you receive a partially valued object (with some fields or association set to null) to merge: the null fields will be set to null in the database, this might not be what you want.
How do you (or would you) handle such situations? Please don't advice me to use DTOs.
In that case, you should use a "manual merge": load the existing entity using find and update yourself the fields you want to update by copying the new state and let JPA detect the changes and flush them to the database.