-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: UserType containing collections
PostPosted: Wed Jan 16, 2008 10:15 pm 
Newbie

Joined: Wed Jan 16, 2008 9:39 pm
Posts: 2
Hibernate version: 3.2.4sp1

I am attempting to use a CompositeUserType to define a polymorphic value type association as suggested by numerous posts. My value type is a bit unusual (although not considered exotic) in that it has a many valued association to another value type.

A -> C <<value type>> ->* E

In this diagram, entity A has a component C which in-turn has a many valued association with composite-element E. And left out of the diagram are the subtypes of C which I think are not directly relevant to the problem. Also I need to mention that A is also subclassed, therefore it would not be possible to merge C and A together without class explosion and code duplication. Normally this would be mapped using a <component> containing a <set> containing a <composite-element>, but as previously mentioned, I need a UserType. I realize that I could map C as an entity, but it would require an extra table containing nothing other than a one-to-one constrained id and a discriminator. The result is undesirable as we would have a non-optimal schema, and compromised object model on top of it.

I tried developing a CompositeUserType to map this and nesting a SetType property type. Notably missing are the column mappings, as i haven't quite figured out how to map these. I am getting a MappingException with the message "Unknown collection role" at runtime, after the application has already initialized, and only after loading/querying for A and flushing.

Some of the more interesting code is here with non-relevant members omitted for clarity:
Code:
public class CType implements CompositeUserType {
  Type[] getPropertyTypes() {
    return new Type[]{new SetType(A.class.getName() + ".c.es", null, true)}
  }
}
public class C {
  private Set<E> es;
}


The schema I would like to create looks like this: non-relevant attributes omitted for clarity.

Code:
a (id, a_discriminator, c_discriminator)
e (a_id)


After delving into the source code with a debugger, I have determined that the SessionFactory's collectionPeristers does not contain a role for the collection of Es within C. It gets these collectionPersisters from the Configuration object's collection mappings. My initial thoughts are that I need to somehow create a "Collection" or "Set" object to add to Mappings.collections, but it's not clear how this can be done as CompositeUserType does not have seem to have hooks to manipulate the Mappings object. My best guess is that I'll need to manipulate the Configuration object by manually adding a collection to the Mappings before building the session factory.

I'd like some advice as to what is the best way to create the mapping.


Top
 Profile  
 
 Post subject: possible compromise
PostPosted: Fri Jan 18, 2008 5:01 pm 
Newbie

Joined: Wed Jan 16, 2008 9:39 pm
Posts: 2
I believe I have a pragmatic way to work around the issue by compromising the model while keeping the optimal schema.

We create a proxy of C containing a property for each subtype of C such that each subtype receives a property on the proxy each property is persisted as an attribute of C. An explicit discriminator property in the proxy will determine the actual type and valid c subtype property to select. For example:
(pseudocode)
Code:
class CProxy extends C {
  property C1 c1;
  property C2 c2;
  property Discriminator d;
  C getActual() {
    if (d == Discriminator.C1) {
      return c1;
    } else if (d == Discriminator.C2) {
      return c2;
    } else { ... }
  }

  void setActual(C c) {
    ...
  }
}

class C1 extends C {}
class C2 extends C {}

// optional implementation of class A
class A {
  CProxy c;
  void c() {
    return c;
  }
  void setC(C c) {
    c.setActual(c);
  }
}


Class A is aware that there is a proxy in place, which means if class A exposes a setter for C, it must wrap a proxy around changes to its c property. However all is not lost, because clients of A need not be aware of the proxy. The consequence is that knowledge about the mapping of the model has leaked into the domain model itself-hence the compromise, however class A encapsulates leakage of that knowledge.

Finally, this can be mapped without employing a UserType because hibernate does not need to be aware of the polymorphic value-type.

This compromise is not ideal, however it does preserve the optimal efficiency of the schema, and keeps the domain model more or less intact at the interface level.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.