Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment créer une classe de modèle d'entité générique prenant en charge les identifiants génériques, y compris les identifiants générés automatiquement ?

Je n'ai pas essayé cela, mais selon l'API d'Hibernate, cela ne devrait pas être compliqué en créant une implémentation personnalisée de IdentityGenerator .

Il s'agit de la méthode de génération d'obtentions et de l'objet pour lequel vous générez la valeur afin que vous puissiez vérifier le type du champ id et renvoyer la valeur appropriée pour votre clé primaire.

public class DynamicGenerator  implements IdentityGenerator

        public Serializable generate(SessionImplementor session, Object object)
                throws HibernateException {

             if (shouldUseAutoincrementStartegy(object)) { // basing on object detect if this should be autoincrement or not, for example inspect the type of id field by using reflection - if the type is Integer use IdentityGenerator, otherwise another generator 
                 return new IdentityGenerator().generate(seession, object)
             } else { // else if (shouldUseTextKey)

                 String textKey = generateKey(session, object); // generate key for your object

                 // you can of course connect to database here and execute statements if you need:
                 // Connection connection = session.connection();
                 //  PreparedStatement ps = connection.prepareStatement("SELECT nextkey from text_keys_table");
                 // (...)

                 return textKey;

            }

        }
    }

Utilisez-le simplement comme stratégie de génération :

@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
    @Id
    @GenericGenerator(name="seq_id", strategy="my.package.DynamicGenerator")
    protected T id;
}

Pour Hibernate 4, vous devez implémenter IdentifierGenerator interface.

Comme ci-dessus est accepté pour Hibernate, il devrait toujours être possible de le créer de manière plus générique pour tout fournisseur "conforme à jpa". Selon l'API JPA dans GeneratedValue annotation, vous pouvez fournir votre générateur personnalisé. Cela signifie que vous pouvez fournir le nom de votre générateur personnalisé et que vous devez implémenter ce générateur pour chaque fournisseur jpa.

Cela signifierait que vous devez annoter BaseEntity avec l'annotation suivante

@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
    @Id
    @GeneratedValue(generator="my-custom-generator")
    protected T id;
}

Vous devez maintenant enregistrer un générateur personnalisé avec le nom "my-custom-generator" pour chaque fournisseur jpa que vous souhaitez utiliser.

Pour Hibernate, cela est fait par l'annotation @GenericGenerator comme indiqué précédemment (en ajoutant @GenericGenerator(name="my-custom-generator", strategy="my.package.DynamicGenerator" à BaseEntity classe sur l'un ou l'autre id champ ou BaseEntity le niveau de la classe devrait suffire).

Dans EclipseLink, je vois que vous pouvez le faire via GeneratedValue annotation et l'enregistrer via SessionCustomizer :

            properties.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,
                    "my.custom.CustomIdGenerator");

public class CustomIdGenerator extends Sequence implements SessionCustomizer {


    @Override
    public Object getGeneratedValue(Accessor accessor,
            AbstractSession writeSession, String seqName) {
        return  "Id"; // generate the id
    }

    @Override
    public Vector getGeneratedVector(Accessor accessor,
            AbstractSession writeSession, String seqName, int size) {
        return null;
    }

    @Override
    protected void onConnect() {
    }

    @Override
    protected void onDisconnect() {
    }

    @Override
    public boolean shouldAcquireValueAfterInsert() {
        return false;
    }

    @Override
    public boolean shouldOverrideExistingValue(String seqName,
            Object existingValue) {
        return ((String) existingValue).isEmpty();
    }

    @Override
    public boolean shouldUseTransaction() {
        return false;
    }

    @Override
    public boolean shouldUsePreallocation() {
        return false;
    }

    public void customize(Session session) throws Exception {
        CustomIdGenerator sequence = new CustomIdGenerator ("my-custom-generator");

        session.getLogin().addSequence(sequence);
    }

}    

Chaque fournisseur doit donner un moyen d'enregistrer le générateur d'identifiant, vous devrez donc implémenter et enregistrer une stratégie de génération personnalisée pour chacun des fournisseurs si vous souhaitez tous les prendre en charge.