EclipseLink Mongodb标准在@Embedded字段上查询



我正在尝试将CriteriaQuery与Eclipselink 2.5.2和MongoDb一起使用。我有以下课程:

用户:

@Entity
@NoSql(dataFormat=DataFormatType.MAPPED)
public class User implements Serializable {
private static final long serialVersionUID = -1;
@Id
@GeneratedValue
@Field(name="_id")
private String id;
@Field(name="USERID")
private String userId;
@Field(name="fullName")
private String fullName;
@Field(name="AGE")
private String age;
@Field(name="STATUS")
private String status;
@Embedded
@Field(name="address")
private Address address = new Address();
...Getters/Setters
}

地址:

@Embeddable
@NoSql(dataFormat=DataFormatType.MAPPED)
public class Address {
@Field(name="addressId")
private String addressId = "";
@Field(name="@addressValue")
private String addressValue = "";
...Getters/Setters
}

当我运行以下标准查询时:

// Criteria
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
// From
Root<User> from = query.from(User.class);
// Filter
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(cb.equal(from.get("address").get("addressValue"), "1234 Main St"));
Predicate[] preds = null;
preds = predicates.toArray(new Predicate[predicates.size()]);
query.where(preds);

我得到以下错误:

Criteria表达式是基元类型,不能再进一步导航。

但是,如果您运行JPQL查询,它运行得很好。

em.createQuery("Select u from User u where u.address.addressValue = :address")
.setParameter("address", "1234 Main St")
.setMaxResults(1).getSingleResult();

为了查询Embedded对象中的字段,我需要做一些特殊的事情吗?如果我只是过滤用户,可以在CriteriaQuery中找到内容。

感谢

注意:下面的答案是不是解决方案,而是详细解释了它目前不起作用的原因。

我已经复制了EclipseLink 2.5.2和MongoDB的问题。几个结论:

  • 看起来MongoDB不支持映射到NoSQL数据的嵌入式字段
  • 为了获得令人满意的解决方案,可能需要创建一个错误报告
  • 我不确定它在其他NoSQL数据库中的表现,因为我没有机会对它们进行交叉检查
  • 该问题可能与所有利用EISCompositeObjectMapping类的NoSQL适配器有关(下面将对此进行详细介绍)

作为临时解决方法考虑通过将其字段直接放置在User实体中来替换可嵌入的Address


以下是我的发现-在persistence.xml 中将eclipselink.logging.metamodel级别设置为FINEST

<properties>
<property name="eclipselink.target-database" value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/>
<property name="eclipselink.nosql.connection-spec" value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/>
<property name="eclipselink.nosql.property.mongo.port" value="27017"/>
<property name="eclipselink.nosql.property.mongo.host" value="127.0.0.1"/>
<property name="eclipselink.nosql.property.mongo.db" value="odm_eclipselink"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.logging.metamodel" value="FINEST"/>
</properties>

显示了EclipseLink+MongoDB的以下输出:

[EL Finest]: metamodel: 2015-05-12 20:33:48.906--Thread(Thread[main,5,main])--Metamodel processing: The mapping type [org.eclipse.persistence.eis.mappings.EISCompositeObjectMapping[address]] in the attribute [SingularAttributeImpl[null,org.eclipse.persistence.eis.mappings.EISCompositeObjectMapping[address]]] is currently unsupported.
[EL Finest]: metamodel: 2015-05-12 20:33:48.906--Thread(Thread[main,5,main])--Metamodel processing: The class type is null for the attribute: SingularAttributeImpl[null,org.eclipse.persistence.eis.mappings.EISCompositeObjectMapping[address]].
[EL Finer]: metamodel: 2015-05-12 20:33:48.906--ServerSession(13500464)--Thread(Thread[main,5,main])--Canonical Metamodel class [eclipselink.User_] found and instantiated during initialization.
[EL Finer]: metamodel: 2015-05-12 20:33:48.906--ServerSession(13500464)--Thread(Thread[main,5,main])--Canonical Metamodel class [eclipselink.Address_] found and instantiated during initialization.

上面的输出清楚地表明,该功能目前不受支持(至少从最终用户的角度来看)。

从静态元模型的角度来看,User.Address嵌入属性由SingularAttribute<User, Address>表示。深入研究,我们可以发现org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl实例化了SingularAttributeImpl<EntityTypeImpl<User>, BasicTypeImpl<Object>>借助于CCD_ 9类,该类定义了属性(地址=可嵌入)如何相对于其父属性(用户=enity)进行聚合和结构化。现在,问题的根本原因很可能是缺乏正确的映射,如下面的org.eclipse.persistence.mappings类层次结构所示:

CoreMapping
|
DatabaseMapping
|
AggregateMapping
|
AbstractCompositeObjectMapping  | @Override
|                          | public Class getAttributeClassification() {
EISCompositeObjectMapping ------|     return null; // root-cause of the problem!
| }    
|   

getAttributeClassification()方法中缺乏实现导致元模型日志中不受支持的映射BasicTypeImpl(而不是EmbeddableTypeImpl)的实例化,这在这种特殊情况下是错误的。


相比之下,EclipseLink+PostgreSQL的相同场景就像一个魅力:

[EL Finer]: metamodel: Canonical Metamodel class [com.wypieprz.jpa.example.model.Address_] found and instantiated during initialization.
[EL Finer]: metamodel: Canonical Metamodel class [com.wypieprz.jpa.example.model.User_] found and instantiated during initialization.

重要的区别在于与SQL数据库相关的org.eclipse.persistence.jpa.PersistenceProvider在比较中使用了不同的映射类MongoDB案例。这一次元模型实现实例化SingularAttributeImpl<EntityTypeImpl<User>, EmbeddableTypeImpl<Object>>AggregateObjectMapping类的帮助下,实现如预期:

CoreMapping
|
DatabaseMapping
|
AggregateMappping            | @Override
|                       | public Class getAttributeClassification() {
AggregateObjectMapping ------|     return getReferenceClass();
| }
|

这一次getAttributeClassification()方法导致在元模型日志中发现并实例化,并实例化预期的EmbeddableTypeImpl

最新更新