如何使用 DataNucleus JDOQL API 查询集合中的对象?

How can I use DataNucleus JDOQL API to Query Object within Collection?

我正在尝试弄清楚如何使用 RDBMS 和 DataNucleus 查询持久对象集合中的对象。我有一个用户、一个 ObjectAttribute 和一个 ObjectAttributeDefinition。

用户可能有多个 ObjectAttribute,每个 ObjectAttribute 都有一个 ObjectAttributeDefinition。这个想法是一些定义可以定义一大堆 ObjectAttributes。

我想检查是否存在一个 ObjectAttribute,其值字段与指定字段一致,并且其 ObjectAttributeDefinition 包含字段 attributeName,其值设置为我指定的 attributeName。

换句话说:

for (ObjectAttribute attribute : userAttributeCollection)
{
    if(attribute.value == myValue && attribute.definition.attributeName == myName)
        return success;
}

我有以下三个class:

用户

@Component
@PersistenceCapable
public class User implements Serializable
{
    @Persistent(table="USER_ATTRIBUTES")
    @Join(column="USER_ID")
    @Element(column = "ATTRIBUTE_ID")
    private List<ObjectAttribute> userAttributeCollection;

    ///... Constructors, getters and setters, Primary Key definition below
}

对象属性

@Component
@PersistenceCapable
public class ObjectAttribute implements Serializable
{
    @Persistent(table="ATTRIBUTE_DEFINITION_JOIN")
    @Join(column="ATTRIBUTE_ID")
    @Element(column="DEFINITION_ID")
    private ObjectAttributeDefinition definition;
    private String value;

    //...

    @Override
    public boolean equals(Object obj)
    {
        ObjectAttribute testObject = (ObjectAttribute) obj;
        if (this.value.equals(testObject.getValue()) && this.definition.getAttributeName().equals(testObject.getDefinition().getAttributeName())) {
            return true;
        }
        else {
            return false;
        }
    }
}

对象属性定义

public class ObjectAttributeDefinition implements Serializable
{
    public enum ATTRIBUTE_NAMES
    {
        //Google Search Page Attribute (https://cloud.google.com/appengine/docs/java/search/)
        SEARCH_PAGE("SEARCH_PAGE");

        private final String text;

        ATTRIBUTE_NAMES(String type)
        {
            this.text = type;
        }

        @Override
        public String toString()
        {
            return text;
        }
    }

    private ATTRIBUTE_NAMES attributeName;

    //...

    @Override
    public boolean equals(Object obj)
    {
        ObjectAttributeDefinition definition = (ObjectAttributeDefinition) obj;
        return this.attributeName.equals(definition.attributeName);
    }

}

进一步说明

我有一个 DAO class 和为访问这些持久对象定义的方法列表。整体基础设施似乎设置正确,因为持久对象和再次检索它们似乎工作正常。

我确保对象属性唯一性的方法是查询 ObjectAttribute 的值和 ObjectAttributeDefinition 的名称。

我试过的

基本查询

        Query query = pm.newQuery(User.class, "userAttributeCollection.contains(att) & att.value == :val & att.definition.attributeName == :def");
        query.declareVariables("ObjectAttribute att");
        query.declareImports("import com.us.orm.general.models.ObjectAttributeDefinition; import com.us.orm.general.models.ObjectAttribute");

        query.setResultClass(User.class);

        rval =  (List<User>) query.execute(myAtt.getValue(), myAtt.getDefinition().getAttributeName());

基本查询错误

Query has reference to member "attributeName" of class "com.us.orm.general.models.ObjectAttribute" yet this doesnt exist!

正如 JDO Specification 所暗示的那样,一切都应该非常 Java。但是,出于某种原因,我似乎无法访问低于第一层的对象。

所以我试图破解比较。

在 ObjectAttribute 中使用 equals() 覆盖

        Query query = pm.newQuery(User.class, "userAttributeCollection.contains(att) & att == :val");
        query.declareVariables("ObjectAttribute att");
        query.declareImports("import com.us.orm.general.models.ObjectAttributeDefinition; import com.us.orm.general.models.ObjectAttribute");

        query.setResultClass(User.class);

        rval =  (List<User>) query.execute(myAtt);

在 ObjectAttribute 结果中使用 equals() 覆盖

我收到零结果。查看为此对象生成的实际 SQL,我得到以下信息:

SELECT DISTINCT 'com.us.orm.user.models.User' AS NUCLEUS_TYPE,`A0`.`CREATED`,`A0`.`EMAIL`,`A0`.`FIRSTNAME`,`A0`.`ISACTIVE`,`A0`.`LASTMODIFIED`,`A0`.`LASTNAME`,`A0`.`PASSWORD`,`A0`.`PROFILEBANNERBUCKET`,`A0`.`PROFILEBANNERFILENAME`,`A0`.`PROFILEIMAGEBUCKET`,`A0`.`PROFILEIMAGEFILENAME`,`A0`.`USERID`,`A0`.`USERNAME` FROM `USER` `A0` INNER JOIN `USER_ATTRIBUTES` `B0` ON `A0`.`USERID` = `B0`.`USER_ID` INNER JOIN `OBJECTATTRIBUTE` `C0` ON `B0`.`ATTRIBUTE_ID` = `C0`.`ATTRIBUTEID` WHERE `C0`.`ATTRIBUTEID` = null

空引用的 ATTRIBUTEID 检查永远不会 return 结果。所以这是在我的代码与 DataNucleus 的接口方面,但我又不知所措了。

也许我可以覆盖 ObjectAttribute 和 ObjectAttributeDefinition 上的 equals()..

等于覆盖 ObjectAttribute 和 ObjectAttributeDefinition

    Query query = pm.newQuery(User.class, "userAttributeCollection.contains(att) & att.value == :val & att.definition == :def");
    query.declareVariables("ObjectAttribute att");
    query.declareImports("import com.up.orm.general.models.ObjectAttributeDefinition; import com.up.orm.general.models.ObjectAttribute");

    query.setResultClass(User.class);

    rval =  (List<User>) query.execute(myAtt.getValue(), myAtt.getDefinition());

等于重写 ObjectAttribute 和 ObjectAttributeDefinition 结果

rval returns null,不生成数据库查询,不抛异常。

仅使用值比较

        Query query = pm.newQuery(User.class, "userAttributeCollection.contains(att) & att.value == :val");
        query.declareVariables("ObjectAttribute att");
        query.declareImports("import com.up.orm.general.models.ObjectAttributeDefinition; import com.up.orm.general.models.ObjectAttribute");

        query.setResultClass(User.class);

        rval =  (List<User>) query.execute(myAtt.getValue());

仅使用值比较结果

这return是期望值,但没有使用定义比较,只达到了目标的一半。

有什么方法可以查询二级深度的定义及其字段吗?

我找到了解决办法。我可能在文档中错过了这一点,但我不知道声明的变量实际上在 SQL 中执行 "cross join"。这是解决问题的一个非常重要的方面。

查询如下:

    Query query = pm.newQuery(User.class, "userAttributeCollection.contains(att) & att.value == :val & definition.attributeName == :name");
    query.declareVariables("ObjectAttribute att; ObjectAttributeDefinition definition");
    query.declareImports("import com.us.orm.general.models.ObjectAttributeDefinition; import com.us.orm.general.models.ObjectAttribute");

    query.setResultClass(User.class);

    rval =  (List<User>) query.execute(myAtt.getValue(), name.toString());

我缺少过滤器的 "cross joined" 变量部分(以 ObjectAttributeDefinition 的形式)。现在它就在那里,查询正在提取预期的结果。