1

I have a class A, with property of class B.

The SQL table for A does not know anything about B.

The SQL table for B contains a foreign key to A.

How can I map (in hbm.xml) so that B is a property of A? I know how to do this with Sets:

<set name="b" table="B" cascade"all-delete-orphan">
    <key column="a_id">
    <composite-element class="B">
        <property name="bProp" column="b_prop" type="string"/>
    </composite-element>
</set>

Thing is, B is NOT a set of A. Rather just a single element. How might I go about mapping this?


Edit: To clarify a bit, my use case is similar to http://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/associations.html#assoc-unidirectional-m21 except instead of:

create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )

I have:

create table Person ( personId bigint not null primary key )
create table Address ( personId bigint, addressId bigint not null primary key )

However, I would expect then that the actual Address Class does not contain any references to Person:

class Person {
    Address address;
}

class Address {
    int id;
}
kennyg
  • 999
  • 2
  • 10
  • 23
  • In your example, since the child class (Address) has the foreign key reference to the parent (Person), this is, in fact, a one-to-many relationship from Person to Address. This schema specifically indicates that a person may have more than one address, but each Address belongs only to one person. – Ian McLaird Aug 28 '14 at 19:31
  • Yeah... I understand. I've brought that up with my team mates but it seems as though too much code is reliant on the db tables staying the way they are. Would it still be possible to map it as a single element rather than a Set? – kennyg Aug 28 '14 at 22:42
  • It's awkward to map a relationship the "wrong" way in an ORM. See http://stackoverflow.com/questions/2452987/hibernate-why-use-many-to-one-to-represent-a-one-to-one – Ian McLaird Aug 29 '14 at 15:41
  • Agreed. I'm pushing for this to be re-factored but like I said my team is pushing back since it touches a lot of code. Are you telling me that there is no way to do what I want to accomplish? – kennyg Aug 29 '14 at 15:55
  • No, of course there's a way (see my answer), it's just clunky. – Ian McLaird Aug 29 '14 at 21:34

2 Answers2

1

I don't especially like this solution, but you can work around the issue by using a couple of wrapper methods. Create a fake getter/setter pair for an unmapped property that gives you the interface you need. Thus:

public class Person {
    private List<Address> addresses;
    // properties, real getters and setters

    public Address getAddress() {
        if (this.addresses == null || this.addresses.isEmpty()) {
            return null;
        }
        return this.addresses.get(0);
    }

    public void setAddress(Address address) {
        if (this.addresses == null) {
            this.addresses = new ArrayList<Address>();
        }
        this.addresses.clear();
        this.addresses.add(address);
    }
}
Ian McLaird
  • 5,507
  • 2
  • 22
  • 31
  • Ouch, definitely not too crazy about this solution, but it's better than nothing. Thanks man. – kennyg Aug 31 '14 at 20:59
0

If anyone else is having trouble with a situation like this, I've finally figured it out. Simply map the second table using a

<join table="Address">
    <key column="personId">
        <component name="address" class="Address">
            <property name="id" column="addressId" type="int" />
        </component>
    </key>
</join>
kennyg
  • 999
  • 2
  • 10
  • 23