2

不明な JPA エンティティがあり、そのバージョンを知る必要があります。これを一般的に行う方法が見つかりませんでした。

メタモデルを試しましたが、getVersion() メソッドに何を渡せばよいかわかりません:

Object entity = ...;
Metamodel metamodel = entityManager.getMetamodel();
IdentifiableType<?> metaClass = 
    (IdentifiableType<?>)metamodel.managedType(entity.getClass());
metaClass.getVersion(<what to put here?>);

で同じパターンが使用されてmetaClass.getId()いますが、補完的な方法がありますgetIdType()--getVersionType()がありません。

第二に、方法はあるがentityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity)方法はないgetVersion(entity)

不明なエンティティからバージョンを取得する方法はありますか?

4

5 に答える 5

2

try/catch の答えよりも少しきれいです:

public static SingularAttribute<?, ?> getVersionAttribute(ManagedType<?> managedType) {
    if (!(managedType instanceof IdentifiableType<?>))
        return null;

    IdentifiableType<?> identifiableType = (IdentifiableType<?>)managedType;
    if (!identifiableType.hasVersionAttribute())
        return null;

    for (SingularAttribute<?, ?> attribute : identifiableType.getSingularAttributes()) {
        if (attribute.isVersion())
            return attribute;
    }
    return null;
}
于 2014-07-07T17:01:28.383 に答える
1

何か不足していますか?バージョン フィールドを公開するバージョン管理可能なエンティティにインターフェイスを実装することで、これを修正します。反省はいらない。

ただし、それはもちろんエンティティ クラスを変更できることを前提としています。

于 2012-11-07T09:19:30.707 に答える
1

私見、そのクラスに @Version アノテーションが付けられたフィールドのタイプを配置する必要があります。これはそのままで、継承でも機能すると思います。

タイプが事前にわからない場合は、標準のリフレクションを使用します。宣言されたすべてのフィールドを繰り返し処理し、注釈に @Version 注釈が含まれているかどうかを確認します。見つからない場合は、見つかるまでスーパークラスを確認してください...

public static Field getVersionField(Object entity) {
    Class<?> myClass = entity.getClass();
    do {
        Field[] fields = myClass.getDeclaredFields();
        for(Field field:fields) {
            if(field.getAnnotation(Version.class)!=null) {
                return field;
            }
        }
    } while((myClass=myClass.getSuperclass())!=null);
    return null;
}

注意: Class.getFields()はパブリック フィールドのみを返すため、より優れた代替手段のように見えますが、機能しません。

この Class オブジェクトによって表されるクラスまたはインターフェイスのすべてのアクセス可能なパブリック フィールドを反映する Field オブジェクトを含む配列を返します。

編集上記は、フィールドで @Version アノテーションが厳密に使用されている場合にのみ機能します。ただし、Konstantin Pribluda が指摘したように、この注釈はメソッドにも付けることができます。これは、次の 2 つのことを意味します。

  • メソッドもチェックする必要があります
  • メソッドはインターフェースによって定義できるため、インターフェースもチェックする必要があります...

これは、単純なサイクルを再帰的なグラフ トラバーサルに変換する必要があることも意味します...

public static Method getVersionMethod(Class<?> myClass) {
    Method[] methods = myClass.getDeclaredMethods();
    for(Method method : methods) {
        if(method.getAnnotation(Version.class)!=null) {
            return method;
        }
    }

    if(myClass.getSuperclass()!=null) {
        Class<?> returned = getVersionMethod(myClass.getSuperclass());
        if(returned!=null) {
            return returned;
        }
    }

    for(Class<?> interfaceToCheck : myClass.getInterfaces()) {
        Class<?> returned = getVersionMethod(interfaceToCheck);
        if(returned!=null) {
            return returned;
        }
    }

    return null;
}
于 2012-11-07T07:52:00.093 に答える
1

私は次の方法で解決しました。javax.persistence.Versionクラスはサポートされているデータ型を指定していますが、サポートされているのは 7 つだけなので、それらすべてを次々と試します。JPA 仕様には明らかにgetVersionType()メソッドがありません。バグだと思います。

/**
 * Finds the version attribute for ManagedType instance.
 * @param managedType The metaobject
 * @return The version attribute or null, if it does not have one
 * @throws UnsupportedOperationException
 * If it has a version attribute, but is not one of supported types, as specified in {@link Version} documentation
 * (currently int, Integer, short, Short, long, Long, Timestamp).
 */
private static <T> SingularAttribute<? super T, ?> findVersionAttribute(ManagedType<T> managedType) {
    if ( !(managedType instanceof IdentifiableType))
        return null;

    IdentifiableType<T> identifiableType = (IdentifiableType<T>)managedType;
    if ( ! identifiableType.hasVersionAttribute())
        return null;

    try {
        return identifiableType.getVersion(int.class);
    } catch (IllegalArgumentException e) {
        try {
            return identifiableType.getVersion(Integer.class);
        } catch (IllegalArgumentException e1) {
            try {
                return identifiableType.getVersion(long.class);
            } catch (IllegalArgumentException e2) {
                try {
                    return identifiableType.getVersion(Long.class);
                } catch (IllegalArgumentException e3) {
                    try {
                        return identifiableType.getVersion(short.class);
                    } catch (IllegalArgumentException e4) {
                        try {
                            return identifiableType.getVersion(Short.class);
                        } catch (IllegalArgumentException e5) {
                            try {
                                return identifiableType.getVersion(Timestamp.class);
                            } catch (IllegalArgumentException e6) {
                                throw new UnsupportedOperationException("The version attribute is not of supported type");
                            }
                        }
                    }
                }
            }
        }
    }
}
于 2012-11-07T15:24:21.880 に答える
1

EclipseLink を使用している場合は、次を使用してバージョンを取得できます。

Session session = em.unwrap(Session.class);
session.getDescriptor(Employee.class).getOptimisticLockingPolicy().getWriteLockValue(object, id, session);
于 2012-11-07T14:35:34.357 に答える