Hi. Can anybody explain me, why i get dublicate Objects (same instanzes) from the resultList of an namedQuery and Joint Fetch?
I have a Object Person with a list of Phones. If the personA has 2 phones, i execute the namedQuery with fetch join and get the correct count of 2 Rows (outer join) from the Database. My resultset has now 2 items of the same persons. But i have only one person with 2 phones. The problem seams the Join. I think, the Query should identify the same objects (to call hashCode or equals) and should only get one item back.
Example: 
Code:
create table person
(
  person_id                bigint not null AUTO_INCREMENT, 
  firstname                varchar(50),
  primary key (person_id) 
) engine=innodb default charset=utf8 ;
create table phone
(
  phone_id         bigint not null AUTO_INCREMENT, 
  phonenumber      varchar(25),
  person_id        bigint not null,
  primary key (phone_id) 
) engine=innodb default charset=utf8 ;
alter table phone add constraint phone_person_fk foreign key (person_id) references person (person_id);
Code:
@Table(name="phone")
public class Phone {
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="phone_id")
        private Long phoneId;
        
        @Column(name="phonenumber")
        private String phoneNumber;
        
        public long getPhoneId() {return phoneId;}
        public void setPhoneId(long phoneId) {this.phoneId = phoneId;}
        public String getPhoneNumber() {return phoneNumber;}
        public void setPhoneNumber(String phoneNumber) {this.phoneNumber = phoneNumber;}
        @Override
        public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + ((phoneId == null) ? 0 : phoneId.hashCode());
                result = prime * result
                                + ((phoneNumber == null) ? 0 : phoneNumber.hashCode());
                return result;
        }
        @Override
        public boolean equals(Object obj) {
                if (this == obj)
                        return true;
                if (obj == null)
                        return false;
                if (getClass() != obj.getClass())
                        return false;
                Phone other = (Phone) obj;
                if (phoneId == null) {
                        if (other.phoneId != null)
                                return false;
                } else if (!phoneId.equals(other.phoneId))
                        return false;
                if (phoneNumber == null) {
                        if (other.phoneNumber != null)
                                return false;
                } else if (!phoneNumber.equals(other.phoneNumber))
                        return false;
                return true;
        }
Code:
@Entity
@Table(name="person")
@NamedQueries( { @NamedQuery(name = "person.loadAll", query = "SELECT p FROM Person p LEFT JOIN FETCH p.phoneList") })
public class Person {
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="person_id")
        private Long personId;
        @Column(name="firstname")
        private String firstName;
        @OneToMany(cascade=CascadeType.ALL)
        @JoinColumn(name="person_id")
        private List<Phone> phoneList;
        
        public Long getPersonId() {return personId;}
        public void setPersonId(Long personId) {this.personId = personId;}
        public String getFirstName() {return firstName;}
        public void setFirstName(String firstName) {this.firstName = firstName; }
        public List<Phone> getPhoneList() {return phoneList;}
        public void setPhoneList(List<Phone> phoneList) {this.phoneList = phoneList;}
        @Override
        public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result
                                + ((firstName == null) ? 0 : firstName.hashCode());
                result = prime * result
                                + ((personId == null) ? 0 : personId.hashCode());
                return result;
        }
        @Override
        public boolean equals(Object obj) {
                if (this == obj)
                        return true;
                if (obj == null)
                        return false;
                if (getClass() != obj.getClass())
                        return false;
                Person other = (Person) obj;
                if (firstName == null) {
                        if (other.firstName != null)
                                return false;
                } else if (!firstName.equals(other.firstName))
                        return false;
                if (personId == null) {
                        if (other.personId != null)
                                return false;
                } else if (!personId.equals(other.personId))
                        return false;
                return true;
        }
I persist one person with 2 phones sucessesfully. Inside table person exist one row with personid 1; 
Inside table phone exists two rows with phoneid 1 and 2 and both with personid 1. 
Code:
Person person = new Person();
person.setFirstName("jon");
Phone phone1 = new Phone();
phone1.setPhoneNumber("020-020222");
Phone phone2 = new Phone();
phone2.setPhoneNumber("0178-2221020222");
List<Phone> phoneList = new ArrayList();
phoneList.add(phone1);
phoneList.add(phone2);
person.setPhoneList(phoneList);
        
em.persist(person);
After this, i will load the person with phoneList 
with only one sql (named query with left outer join). 
Code:
Query q = em.createNamedQuery("person.loadAll");
Collection<Person> c = (List<Person>)q.getResultList();
The resulting sql (correct) gets 2 rows. 
Code:
select
        person0_.person_id as person1_1_0_,
        phonelist1_.phone_id as phone1_7_1_,
        person0_.firstname as firstname1_0_,
        phonelist1_.phonenumber as phonenum2_7_1_,
        phonelist1_.person_id as person3_0__,
        phonelist1_.phone_id as phone1_0__ 
    from
        person person0_ 
    left outer join
        phone phonelist1_ 
            on person0_.person_id=phonelist1_.person_id
The List c now has 2 same Objects inside! I think, it should be only one person. Whats wrong? Thanks for every tip. alex