Backbone js +需要js +骨干关系+循环依赖+自引用

时间:2014-01-17 00:02:17

标签: javascript backbone.js circular-dependency backbone-relational self-reference

我最近遇到了Backbone和Require JS的问题,因为我们需要表示一个相当复杂的数据模型,这会导致循环依赖和自引用问题。我在网上看了很多帖子(其中没有一个真的有用),但我想我找到了一个解决方案。因此,我希望能够分享这一点,希望它能帮助那些遇到这个问题的人,但也会问你们,如果你认为有办法整理一下。

第一个问题是我有一些模型引用了引用模型的集合,这些模型引用了集合,所有模型都创建了一个大的凌乱的循环依赖。坦率地说,这打破了申请。这是一个伪代码示例:

Model A
  has Collection B

Collection B
  of Model B

Model B
  has Collection A
  has Collection C

Collection A
  of Model A

Collection C
  of Model C

Backbone docs表明这可以通过以下方式实现:

  initialize: function() {
    this.messages = new Messages;
    this.messages.url = '/mailbox/' + this.id + '/messages';
    this.messages.on("reset", this.updateCounts);
  },

我尝试了各种方法来满足我们的需求,但是我们复杂的嵌套要求打破了Backbone的局面。所以我偶然发现backbone relational并创建了我们数据模型的基本工作表示(这涉及创建一个与Require JS一起使用的垫片)。实质上这是有效的。所以我扩展了示例,以便Model C也可以拥有Collection C的实例(自引用)。这似乎再次起作用。优秀。但是,将示例应用于我的应用程序更加困难 - 将模型和集合拆分为单个文件证明更加困难,因为主干关系要求集合和模型名称位于全局名称空间(使用Require和“use strict”有点棘手) 。由于我们的复杂数据模型,我想使用字符串标识符来表示关系,而不是显式的需求引用,这也证明是困难的。我尝试将所有内容添加到exports命名空间,但这又不起作用。无论如何,我认为通过将集合和模型添加到自定义命名空间,然后将此命名空间添加到backbonerelational模型范围,我找到了一个解决方案。我把我的自定义库命名为“Orca”(因为虎鲸非常棒)。

bootstrap.js

require.config({
  paths: {
    "jquery"        : "../bower_components/jquery/jquery",
    "underscore"    : "../bower_components/underscore-amd/underscore",
    "backbone"      : "../bower_components/backbone-amd/backbone",
    "relational"    : "../bower_components/backbone-relational/backbone-relational",
    ...

  shim: {
    "underscore": {
      exports: "_"
    },
    "backbone": {
      deps: ["underscore", "jquery"],
      exports: "Backbone"
    },
    "relational": {
      deps: ["backbone"]
    },
    ...

app.js

define(["backbone", "relational", "libs/orca", "collections/a", "models/a", "collections/b", "models/b", "collections/c", "models/c"], function(Backbone, Relational, Orca){
  "use strict";

  var App = function(options) {
    this.initialize(otions);
  }; 

  App.prototype = _.extend(Backbone.Events, {

    initialize: function(options) {
      Orca.initialize();

      var a = new Orca.Relational.ModelA([],{});
    }
  }

  return App;
});

LIB / orca.js

define(["backbone", "relational"], function(Backbone) {
  "use strict";

  var Orca = {
    Relational: {},

    initialize: function() {
      Backbone.Relational.store.addModelScope(this.Relational);      
    }
  };

  // I actually extend Backbone.RelationalModel so I can have custom methods,
  // e.g. "parse" but I've simplified the code for example's sake...
  Orca.Model = Backbone.RelationalModel;
  Orca.Collection = Backbone.Collection;

  return Orca;
});

集合/ a.js

define(["backbone", "libs/orca"], function(Backbone, Orca) {
  "use strict";

  Orca.Relational.CollectionA = Backbone.Collection.extend({});
});

模型/ a.js

define(["backbone", "libs/orca"], function(Backbone, Orca) {
  "use strict";

  Orca.Relational.ModelA = Orca.Model.extend({
    relations: [
      {
        type: Backbone.HasMany,
        key: "bs",
        relatedModel: "ModelB",
        includeInJSON: Backbone.Model.prototype.idAttribute,
        collectionType: "CollectionB",
        reverseRelation: {
          key: "a"
        }
      }
    ]
  });
});

CollectionB和ModelB类似,所以为了简洁我省略了这些。

展示自我指涉:

define(["backbone", "libs/orca"], function(Backbone, Orca) {
  "use strict";

  Orca.Relational.ModelC = Orca.Model.extend({
    relations: [
      {
        type: Backbone.HasMany,
        key: "cs",
        relatedModel: "ModelC",
        includeInJSON: Backbone.Model.prototype.idAttribute,
        collectionType: "CollectionC",
        reverseRelation: {
          key: "c"
        }
      }
    ]
  });
});

所以关于这段代码我的错误是在app.js中我创建了一个ModelA的新实例。但是因为它引用了CollectionB,而ModelB又被ModelB使用,而ModelB又引用了Collection C并使用了Model C,那么我必须将所有这些引用为require依赖项。有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

我实际上已经停止使用Backbone Relational,现在我正在使用JJRelational,因为它允许多对多关系。我还通过创建一个名为“relational.js”的新文件来否定从主应用程序文件中引用集合和模型的需要,该文件引用集合和模型并将它们作为对象的属性返回。这样,如果我需要新的模型或集合,我只需要“relational.js”。

我的relational.js文件看起来有点像这样:

define([
  // Models
  "models/broadcast",
  "models/version",
  // Collections
  "collections/broadcasts",
  "collections/versions"

], function(
  // Models
  Broadcast,
  Version,
  // Collections
  Broadcasts,
  Versions
) {
  "use strict";

  var _relational = {
    Broadcast: Broadcast,
    Version: Version,  

    Broadcasts: Broadcasts,
    Versions: Versions,
  };

  // Register the Collections
  Backbone.JJRelational.registerCollectionTypes({
    "Broadcasts": _relational.Broadcasts,
    "Versions": _relational.Versions    
  });

  // Provide JJRelational with model scope - pull request submitted to JJRelational to handle this
  Backbone.JJStore.addModelScope(_relational);

  return _relational;
});

然后在我的主app.js中:

define(["libs/relational"], function(Relational){
  var broadcast = new Relational.Broadcast();
});

答案 1 :(得分:0)

你有没有提过Backbone Associations。我建议你看看一次。

当我使用它时,我遇到了类似的循环依赖和自引用问题。原因是我已将客户端Models映射到后端的Beans,后者使用Tables映射到Hibernate。在one-to-many中指定Hibernate关系时,您需要将一个实体的引用指定为其他实体,反之亦然。然后,当Jersey服务返回这些实体时,转换为JSON具有循环依赖性。我可以使用some annotations在后端进行删除。但是没有办法在Backbone方面解决它。我向Backbone Associations的作者提出了这个问题并修复了它。

希望这在某些方面有所帮助。