Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iBatis Discriminator on Insert

Tags:

java

ibatis

I have an abstract class Example and concrete subclasses to go along with it. I used a discriminator to pull data out of the database, like so:

<resultMap id="ExampleResultMap" class="Example">
    <discriminator column="stateCode" javaType="java.lang.String">
        <subMap value="AL" resultMap="AlabamaStateResultMap"/>
        <subMap value="AR" resultMap="ArkansasStateResultMap"/>
        [...]
    </discriminator>
</resultMap>

<resultMap extends="ExampleResultMap" 
           id="AlabamaStateResultMap"
           class="AlabamaState"/>
<resultMap extends="ExampleResultMap" 
           id="ArkansasStateResultMap"
           class="ArkansasState"/>
[...]

Thus I have an AlabamaState object (a subclass of the abstract Example object) with no attributes of any kind on him. This is contrived, but the gist is that I don't have any attribute that uniquely identifies the object's type--and there's no reason I would if not for this case.

(Note: The classes aren't empty, they're behavioral, so refactoring them out of existence isn't an option.)

How do I save it back to the database?

Ideally there would be a Discriminator for ParameterMaps, but there doesn't seem to be one.

As far as I can tell, there are a number of undesirable solutions, among them:

  • Give up and add a "getType()" method on all my subclasses that returns a static string. In this case, AL. (Note that I tried pretty hard to avoid needing this throughout all my code, so having this = OOD-defeat).
  • Make a "DB" object that's exactly like my big, complex object but happens to also have an extra string saying "Oh, btw, my TYPE is AL."
  • Extract all 20 attributes I want to persist into a HashMap before inserting the object.
  • Some other craziness like using the toString() or something to help me out.

Likely I'll go with the first option, but it seems rather ridiculous, doesn't it? If iBatis can create it, shouldn't it be able to persist it? What I really need is a discriminator for insert.

Am I out of luck, or am I just overlooking something obvious?

like image 590
inanutshellus Avatar asked Aug 15 '11 20:08

inanutshellus


1 Answers

If you have no attributes belonging to your subclasses, you should consider removing these subclasses and add an enum to your former base-class, since the only purpose your subclasses serve is to differentiate the type of your objects (if I understood you correctly). Using an enum for this is easier to extend and more elegant in client code (since you can switch on the enum instead of using blocks of instanceof expressions).

If are having special implementations of certain operations on your subclasses, you could move them to the enum as well, and have your base class delegate to the implementation on the enum.

EDIT

Here is an example:

public interface GreetingStrategy {
    abstract String sayHello();
}

enum UserType implements GreetingStrategy {
    ADMIN {
        @Override
        public String sayHello() {
            return "hello from admin";
        }
    },

    GUEST {
        @Override
        public String sayHello() {
            return "hello from guest";
        }
    };

}

class User {

    private final GreetingStrategy greetingStrategy;

    public User(GreetingStrategy greetingStrategy) {
        this.greetingStrategy = greetingStrategy;
    }

    public String sayHello() {
        return greetingStrategy.sayHello();
    }

}
like image 97
mbelow Avatar answered Oct 22 '22 08:10

mbelow