如何忽略ExtJS数据模型中的空字段?

dav*_*tto 5 javascript extjs models extjs4.1

我的问题很长......所以,请耐心等待:)

我正在使用ExtJS 4中的模型,但是我在关联方面遇到了一些问题,因此我创建了一个函数来为我执行自动模型创建.让我们假设我需要解析以下JSON:

{ 
    "success": true, 
    "total": 28, 
    "itens": [{
        "id":1,
        "nome":"ACRE",
        "sigla":"AC",
        "pais":{
            "id":31,
            "nome":"BRASIL",
            "sigla":"BR"
        }
    },{
        "id":2,
        "nome":"ALAGOAS",
        "sigla":"AL",
        "pais":{
            "id":31,
            "nome":"BRASIL",
            "sigla":"BR"
        }
    }, ...]
}
Run Code Online (Sandbox Code Playgroud)

itens代表省份(巴西葡萄牙语的Estados),其中有一个国家(巴西葡萄牙语País).我试图使用ExtJS关联,但我认为它就像Java关系一样,我错了.好吧,对于这个JSON,我有这些Java类和这些Ext模型(模型也是使用提供的函数创建的).

Pais.java

@Entity
// named queries here...
public class Pais implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    @NotEmpty
    @Length( max = 100 )
    private String nome;

    @NotNull
    @NotEmpty
    @Column( unique = true )
    @Length( min = 2, max = 4 )
    private String sigla;

    // getters, setters, equals, hashCode and toString here

}
Run Code Online (Sandbox Code Playgroud)

Estado.java

@Entity
// named queries here...
public class Estado implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    @NotEmpty
    @Length( max = 100 )
    private String nome;

    @NotNull
    @NotEmpty
    @Column( unique = true )
    @Length( min = 2, max = 4 )
    private String sigla;

    @NotNull
    @ManyToOne
    private Pais pais;

    // getters, setters, equals, hashCode and toString here

}
Run Code Online (Sandbox Code Playgroud)

创建模型的功能

Ext.ns( "Uteis" );

// other utility functions here...

Uteis.createModel = function( modelData ) {

    var fields = modelData.fields;
    var processedFields = [];
    var normalFields = [];
    var relationFields = [];

    for ( var i in fields ) {

        if ( fields[i].type ) {

            switch ( fields[i].type ) {

                case "auto":
                case "string":
                case "int":
                case "float":
                case "boolean":
                case "date":
                    normalFields.push( fields[i] );
                    break;

                default:

                    var relationField = fields[i];

                    var prefix = relationField.name + ".";
                    var modelInstance = Ext.create( relationField.type );

                    modelInstance.fields.each( function( item, index, length ) {

                        var newField = {};

                        // I used this sintax to make possible create only some fields
                        // if I need in the future.
                        newField["name"] = prefix + item.name;
                        newField["type"] = item.type.type;

                        newField["convert"] = item.convert;
                        newField["dateFormat"] = item.dateFormat;
                        newField["defaultValue"] = item.defaultValue;
                        newField["mapping"] = item.mapping;
                        newField["persist"] = item.persist;
                        newField["sortDir"] = item.sortDir;
                        newField["sortType"] = item.sortType;
                        newField["useNull"] = item.useNull;

                        relationFields.push( newField );

                    });

                    break;

            }

        } else {
            normalFields.push( fields[i] );
        }

    }

    processedFields = normalFields.concat( relationFields );

    // debugging code
    /*console.log( "*** " + modelData.name );
    for ( var i in processedFields ) {
        console.log( processedFields[i] );
    }*/

    Ext.define( modelData.name, {
        extend: "Ext.data.Model",
        fields: processedFields
    });

};
Run Code Online (Sandbox Code Playgroud)

使用函数创建模型

Uteis.createModel({ 
    name: "Modelos.Pais",
    fields: [
        { name: "id",  type: "int" },
        { name: "nome",  type: "string" },
        { name: "sigla",  type: "string" }
    ]
});

Uteis.createModel({ 
    name: "Modelos.Estado",
    fields: [
        { name: "id",  type: "int" },
        { name: "nome",  type: "string" },
        { name: "sigla",  type: "string" },
        { name: "pais", type: "Modelos.Pais" } // <= references the model created above
    ]
});
Run Code Online (Sandbox Code Playgroud)

上面的代码与此相对应.我创建了自动化嵌套数据字段创建的函数(因为我说的关联问题).

Ext.define( "Modelos.Pais", {
    extend: "Ext.data.Model",
    fields: [
        { name: "id",  type: "int" },
        { name: "nome",  type: "string" },
        { name: "sigla",  type: "string" }
    ]
});

Ext.define( "Modelos.Estado", {
    extend: "Ext.data.Model",
    fields: [
        { name: "id",  type: "int" },
        { name: "nome",  type: "string" },
        { name: "sigla",  type: "string" },
        { name: "pais.id",  type: "int" },
        { name: "pais.nome",  type: "string" },
        { name: "pais.sigla",  type: "string" }
    ]
});
Run Code Online (Sandbox Code Playgroud)

好的,这些模型(使用我的createModel函数创建)与我的JsonStores非常兼容.到目前为止,Java端的所有映射关联都不为null,因此,我的商店总是有嵌套数据要处理.现在,我必须处理一些可以具有空关联的实体,并且我的问题就开始了.需要处理此场景的商店不起作用(在存储操作中抛出异常,表示字段为空).我正在使用Gson从我的实体创建JSON.它的默认行为是不对序列化空字段,它们将在客户端未定义,所以我虽然如果我序列化空字段(发送null)将使Ext实现空字段而不是尝试处理它.为此,我使用此代码创建Gson:

Gson gson = new GsonBuilder().serializeNulls().create();
Run Code Online (Sandbox Code Playgroud)

好的,现在正在生成具有空关联的JSON,但是Ext继续抱怨.我试图使用字段映射和defaultValue配置没有成功.为了简单起见,让我们使用Estados和Países(Privinces和Countries)的例子,其中Pais不再是@NotNull.带有空pais的JSON就像:

{ 
    "success": true, 
    "total": 28, 
    "itens": [{
        "id":1,
        "nome":"ACRE",
        "sigla":"AC",
        "pais":null   // <= here
    },{
        "id":2,
        "nome":"ALAGOAS",
        "sigla":"AL",
        "pais":{  // this is not null
            "id":31,
            "nome":"BRASIL",
            "sigla":"BR"
        }
    }, ...]
}
Run Code Online (Sandbox Code Playgroud)

使用此代码,pais.id,pais.nome和pais.sigla字段将不可用,因为pais属性为null.所以,我的问题是:当存储空为null或未定义时,如何使存储忽略某些字段?我已经尝试寻找一个没有成功的解决方案......非常感谢你!

编辑:在服务器端的一些可能的解决方案中考虑整个晚上之后,我在最后15分钟内实现了一个解决方案,但我确实不喜欢它...它是一种在使用之前遍历每个对象"对象树"的反射方法Gson将默认值设置为null的字段.它正在运行,但JSON变得越来越不必要.遍历方法:

/**
 * A method to traverse the object tree and set "default" values to null fields.
 * 
 * @param target The object to be inspected.
 */
public static void traverseAndSetDefaultValue( Object target ) {

    try {

        for ( Field f : target.getClass().getDeclaredFields() ) {

            // ok to change...
            f.setAccessible( true );

            // is null? so create something
            if ( f.get( target ) == null ) {

                // new instance of the current field
                Object newInstance = null;

                // it needs to traverse to the next level?
                boolean okToTraverse = false;

                switch ( f.getType().getSimpleName() ) {

                    case "Byte":
                    case "Short":
                    case "Integer":
                        newInstance = 0;
                        break;

                    case "Long":
                        newInstance = 0L;
                        break;

                    case "Float":
                        newInstance = 0F;
                        break;

                    case "Double":
                        newInstance = 0D;
                        break;

                    case "Character":
                        newInstance = '\0';
                        break;

                    case "Boolean":
                        newInstance = Boolean.FALSE;
                        break;

                    case "String":
                        newInstance = "";
                        break;

                    case "List":
                        newInstance = new ArrayList();
                        break;

                    case "Set":
                        newInstance = new HashSet();
                        break;

                    default:
                        // calling the default constructor for no 
                        // "default" types
                        newInstance = f.getType().newInstance();
                        okToTraverse = true;
                        break;

                }

                f.set( target, newInstance );

                if ( okToTraverse ) {
                    traverseAndSetDefaultValue( newInstance );
                }

            }

        }

    } catch ( IllegalAccessException | InstantiationException exc ) {
        exc.printStackTrace();
    }

}
Run Code Online (Sandbox Code Playgroud)

我想你怎么看...谢谢!

编辑2:再次问好.我放弃!:)我将使用我在上面发布的解决方案.我发现了一些补丁来改善与模型和网格的关系.我测试了它们,但是空字段的问题仍然存在(至少错误消失了).好的,现在是时候继续开发了.应用程序完成后,我将回到此问题,尝试改进我的解决方案.谢谢!

Aus*_*eco 1

不太确定这是否是问题所在,因为您没有给出确切的错误;但我之前遇到过可选嵌套数据的问题,解决方案是在模型中创建一个映射函数:

Ext.define( "Modelos.Estado", {
    extend: "Ext.data.Model",
    fields: [
        { name: "id",  type: "int" },
        { name: "nome",  type: "string" },
        { name: "sigla",  type: "string" },
        { name: "pais.id",  type: "int", mapping: function( o ) { return o.pais ? o.pais.id : null; } },
        { name: "pais.nome",  type: "string", mapping: function( o ) { return o.pais ? o.pais.nome : null; } },
        { name: "pais.sigla",  type: "string", mapping: function( o ) { return o.pais ? o.pais.sigla : null; } }
    ]
});
Run Code Online (Sandbox Code Playgroud)