ExtJS 模型与 jsonapi 规范的关联

Posted

技术标签:

【中文标题】ExtJS 模型与 jsonapi 规范的关联【英文标题】:ExtJS model associations with jsonapi specification 【发布时间】:2021-04-01 01:04:51 【问题描述】:

我们正在创建一个采用 JSON:API 规范 (https://jsonapi.org/) 的 API (v2) 新版本。我无法将 ExtJS 模型关联 (belongs_to) 移植到新模式。

ExtJS 文档只展示了如何在同一个根节点 (https://docs.sencha.com/extjs/4.2.2/#!/api/Ext.data.association.Association) 中使用嵌套关系。

v1 数据(样本):


  "data": [
    
      "id": 1,
      "description": "Software Development",
      "area_id": 1,
      "area": 
        "id": 1,
        "code": "01",
        "description": "Headquarters"
      
    ,
  ],
  "meta": 
    "success": true,
    "count": 1
  

v2 数据(样本):


  "data": [
    
      "id": "1",
      "type": "maint_service_nature",
      "attributes": 
        "id": 1,
        "description": "Software Development",
        "area_id": 1
      ,
      "relationships": 
        "area": 
          "data": 
            "id": "1",
            "type": "area"
          
        
      
    
  ],
  "included": [
    
      "id": "1",
      "type": "area",
      "attributes": 
        "id": 1,
        "code": "01",
        "description": "Headquarters"
      
    
  ],
  "meta": 
    "success": true,
    "count": 1
  

我的模特:

    Ext.define('Suite.model.MaintServiceNature', 
        extend: 'Ext.data.Model',
    
        fields: [
             desc: "Id", name: 'id', type: 'int', useNull: true ,
             desc: "Area", name: 'area_id', type: 'int', useNull: true ,
             desc: "Description", name: 'description', type: 'string', useNull: true, tableIdentification: true 
        ],
    
        associations: [
            
                type: 'belongsTo',
                model: 'Suite.model.Area',
                foreignKey: 'area_id',
                associationKey: 'area',
                instanceName: 'Area',
                getterName: 'getArea',
                setterName: 'setArea',
                reader: 
                    type: 'json',
                    root: false
                
            
        ],
    
        proxy: 
            type: 'rest',
            url: App.getConf('restBaseUrlV2') + '/maint_service_natures',
            reader: 
                type: 'json',
                root: 'data',
                record: 'attributes',
                totalProperty: 'meta.count',
                successProperty: 'meta.success',
                messageProperty: 'meta.errors'
            
        
    );

关于如何设置关联以处理 v2 数据的任何想法?

【问题讨论】:

我认为您将不得不推出自己的阅读器类...该框架未设置为处理这些类型的结构。 【参考方案1】:

老实说,我正在尝试这个...我已经很多年没有使用过 Ext JS 4,而且我不会像 JSON:API 那样构建我的 JSON,但我认为你可以完成的唯一方法这是通过滚动您自己的reader 课程。鉴于您的数据结构具有通用属性,这个阅读器应该适用于所有场景......虽然,我对 JSON:API 不太熟悉,所以我可能完全错了。无论哪种方式,this 都是我想出的。

Ext.application(
    name: 'Fiddle',

    launch: function () 
        Ext.define('MyReader', 
            extend: 'Ext.data.reader.Json',
            alias: 'reader.myReader',

            root: 'data',
            totalProperty: 'meta.count',
            successProperty: 'meta.success',
            messageProperty: 'meta.errors',

            /**
             * @override
             */
            extractData: function (root) 
                var me = this,
                    ModelClass = me.model,
                    length = root.length,
                    records = new Array(length),
                    dataConverter,
                    convertedValues, node, record, i;

                for (i = 0; i < length; i++) 
                    node = root[i];
                    var attrs = node.attributes;
                    if (node.isModel) 
                        // If we're given a model instance in the data, just push it on
                        // without doing any conversion
                        records[i] = node;
                     else 

                        // Create a record with an empty data object.
                        // Populate that data object by extracting and converting field values from raw data.
                        // Must pass the ID to use because we pass no data for the constructor to pluck an ID from
                        records[i] = record = new ModelClass(undefined, me.getId(attrs), attrs, convertedValues = );

                        // If the server did not include an id in the response data, the Model constructor will mark the record as phantom.
                        // We  need to set phantom to false here because records created from a server response using a reader by definition are not phantom records.
                        record.phantom = false;

                        // Use generated function to extract all fields at once
                        me.convertRecordData(convertedValues, attrs, record, me.applyDefaults);

                        if (me.implicitIncludes && record.associations.length) 
                            me.readAssociated(record, node);
                        
                    
                

                return records;
            
        );

        Ext.define('Suite.model.Area', 
            extend: 'Ext.data.Model',

            fields: [
                name: 'type',
                type: 'string'
            ]
        );

        Ext.define('Suite.model.MaintServiceNature', 
            extend: 'Ext.data.Model',

            fields: [
                desc: "Id",
                name: 'id',
                type: 'int',
                useNull: true
            , 
                desc: "Area",
                name: 'area_id',
                type: 'int',
                useNull: true
            , 
                desc: "Description",
                name: 'description',
                type: 'string',
                useNull: true,
                tableIdentification: true
            ],

            associations: [
                type: 'belongsTo',
                model: 'Suite.model.Area',
                associatedName: 'Area',
                foreignKey: 'area_id',
                associationKey: 'relationships.area.data',
                instanceName: 'Area',
                getterName: 'getArea',
                setterName: 'setArea'
            ],

            proxy: 
                type: 'rest',
                url: 'data1.json',
                reader: 
                    type: 'myReader'
                
            
        );

        Suite.model.MaintServiceNature.load(null, 
            callback: function (record) 
                console.log(record.getData(true));
            
        );
    
);

【讨论】:

感谢您抽出宝贵时间提供帮助。使用您的解决方案,我在该区域内的记录中有来自 data.relationships.area 的数据。但是如何从我记录的 Area 中的 area 类型的 included.attributes 中获取数据?例如,这是在网格上显示关系数据所必需的。 哦,对不起...这个结构太混乱了,我不明白你需要什么。我认为您必须取消 root 属性并设置在数据中查找位置的逻辑。

以上是关于ExtJS 模型与 jsonapi 规范的关联的主要内容,如果未能解决你的问题,请参考以下文章

Extjs 4.1 多对多模型关联

ExtJS 4.1 - 检索嵌套 JSON 的 hasOne 信息

为啥我的带有关联的简单 ExtJS 数据示例不起作用?

laravel5 怎么获取数组形式的数据

使用 hasMany 关联在 ExtJS 中填充存储

Capybara 请求规范与 JS 的问题 - 找不到模型