简体   繁体   中英

Grails: map domain class field on composite key

I have a domain class reverse engineered from a legacy table

class AuditLog {

    String className;
    String eventName;
    ...
    AuditEvent event; //need to add this one

    static mapping = {
        ...
        className column: 'class_name';
        eventName column: 'event_name';
        ...
    }
}

className contains the name of domain class that was changed (eg com.test.Class1) and eventName contains the name of the event performed (eg INSERT/UPDATE/DELETE).

I need to provide a human-readable description of what happened. So I created another domain class

class AuditEvent {

    String name;

    //these should make a composite key
    String className; 
    String eventName;

}

eg AuditEvent[name:"Row inserted into Class1", className:"com.test.Class1", eventName:"INSERT"].
AuditEvent[name:"Row deleted from Class1", className:"com.test.Class1", eventName:"DELETE"]

What I want now is to be able to call AuditLog.get(1).event.name and this is where I'm stuck.

How do I describe the relation for the event field in AuditLog class to make it load the right AuditEvent object depending on AuditLog.className and AuditLog.eventName?

Since the classname and eventname are in the AuditEvent object, you don't need them in the AuditLog class. You will, however have to create/lookup the AuditEvent when you create your AuditLog instances. ie. The two fields won't automatically be injected:

new AuditLog(event: AuditEvent.findOrSaveWhere(className: .., eventName: ..)).save()

You may be better off not making the association in the classes, but rather have a method on the AuditLog class which looks up the AuditEvent:

class AuditEvent {
    // ..
    static AuditEvent get(className, eventName) {
        find 'from AuditEvent e where e.className = :className and e.eventName = :eventName', [className: className, eventName: eventName]
    }
}

class AuditLog {

    String className;
    String eventName;

    // ...

    String getEventName() {
        AuditEvent.get(className, eventName).name
    }
}

That would make your name lookup like:

AuditLog.get(id).eventName

Why do you need a composite primary key for AuditEvent ?

What about hasOne ?

class AuditLog {
    static hasOne = [event: AuditEvent]
}

class AuditEvent {

    String name

    AuditLog auditLog 

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM