javascript ORM

javascript ORM

前端ORM框架其实也就是一个对于DAO数据访问接口的封装,主要是封装CRUD四种类型基本操作。
所谓对象关系映射的构建,最基本的还是在于模型这一层,也就是数据模型,我们应该用对象来封装我们的数据,以形成模型。
例如一个基本的数据结构为:

1 var data = {
2     name: 'ken',
3     age: 18
4 };

我们需要将这样一个数据转化为一个对象,可以将之作为一个参数传递到一个具有某些功能的对象中去,例如:

 1 function Model(data) {
 2     this.data = data;
 3 }
 4 Model.prototype.save = function() {
 5     //do create or update
 6 };
 7 Model.prototype.read = function() {
 8     
 9 };
10 Model.prototype.delete = function() {
11     
12 };
13 Model.prototype.get = function(attr) {
14     return this.data[attr];
15 };

上面的代码定义了一个基本的数据模型,这个能够完成与服务器之间的数据交互,而数据最终还是需要展现在页面上的,这就需要另外一个对于数据和视图之间的处理了。数据变化之后能够通知页面进行重新渲染,我们可以使用比较常用的一种设计模式,也就是发布/订阅模式来完成这种事件的交互。在数据层发布事件,在视图层去监听事件。我们可以在网上找到很多实现了该功能的代码,其原理也很简单,只需要维护一个用于保存事件名和相应事件的Map表即可,下面是一个实现代码:

 1 var Events = Spine.Events = {
 2     bind: function(ev, callback) {
 3       var evs   = ev.split(" ");
 4       var calls = this._callbacks || (this._callbacks = {});
 5       
 6       for (var i=0; i < evs.length; i++)
 7         (this._callbacks[evs[i]] || (this._callbacks[evs[i]] = [])).push(callback);
 8 
 9       return this;
10     },
11 
12     trigger: function() {
13       var args = makeArray(arguments);
14       var ev   = args.shift();
15             
16       var list, calls, i, l;
17       if (!(calls = this._callbacks)) return this;
18       if (!(list  = this._callbacks[ev])) return this;
19       
20       for (i = 0, l = list.length; i < l; i++)
21         if (list[i].apply(this, args) === false)
22           return false;
23       return this;
24     },
25 
26     unbind: function(ev, callback){
27       if ( !ev ) {
28         this._callbacks = {};
29         return this;
30       }
31       
32       var list, calls, i, l;
33       if (!(calls = this._callbacks)) return this;
34 
35       if (!(list  = this._callbacks[ev])) return this;
36       
37       if (!callback) {
38         delete this._callbacks[ev];
39       }
40       
41       for (i = 0, l = list.length; i < l; i++) {
42         if (callback === list[i]) {
43           list.splice(i, 1);
44           break;
45         }
46       }
47         
48       return this;
49     }
50   };

我们可以给任何需要用到发布订阅模式的对象继承该Event对象,然后我们便可以很方便的发布/订阅事件了。
当然,我们的对象默认情况下并没有一个可直接使用的继承方法,但是要实现基层并不难,我们可以给我们的Model对象添加下面这两个方法:

 1 Model.include = function(obj){
 2   for(var key in obj) {
 3       this.prototype[key] = obj[key];
 4   }
 5 
 6   var included = obj.included;
 7   if (included) included.apply(this);
 8   return this;
 9 },
10 
11 Model.extend = function(obj){
12   for(var key in obj) {
13       this[key] = obj[key];
14   }
15   
16   var extended = obj.extended;
17   if (extended) extended.apply(this);
18   return this;
19 }

有了上面的两个方法之后,我们便可以通过include方法来扩展实例方法,通过extend来扩展静态方法,对于Event,我们可以用extend来进行扩展:

1 Model.extend(Event);

扩展完成之后,我们便可以在我们的代码中添加事件的发布或者订阅了,在模型中有关于数据保存或者更新的地方我们可以发布change事件,在数据销毁的时候我们可以发布destroy事件:

1 Model.prototype.save = function() {
2     //todo create or update
3     this.trigger('change');
4 };
5 Model.prototype.delete = function() {
6     //todo delete
7     this.trigger('destroy');
8 }

在页面中,我们会根据得到的数据来生成对应的模型,因为我们的模型已经扩展了发布订阅模式,因此在代码中,我们给我们的模型添加订阅事件的代码:

1 //子视图
2 function View(data) {
3     var model = new Model(data);
4     model.bind('change', this.render);
5 }
6 View.prototype.render = function() {
7     //todo view render
8 };

上面便是前端ORM的一个基础框架模型,也是核心点所在,不过要完成整个框架,仍然需要添加很多的东西。
上面的代码仅仅是能实现唯一的模型实例,而不能对模型实例集合进行操作,什么意思呢,比如你的数据是一个数组,
里面包含了多条数据,没一条数据都能转换为一个对象的模型对象。在现在的代码中,我们只完成了一条数据的转换而没有完成整个数据数据的转换,因此,需要做出一些调整;
在服务器端获取回来的数据,我们应该将之转换为一个模型,数据集里面的每一个数据记录,就用来转换成为该模型的每一个实例,按照这个思路,我们的代码使用起来可能像下面这个样子:

1 var User = Model.create();
2 var user = User.init();

模型的创建,也就是User的创建,我们是不需要传递数据的,只需要传递我们需要的一些数据字段即可,这些字段也就是模型实例的一些内置属性;根据User来生成的实例都会具有User所具有的一些信息,在这里就是字段属性。
同时Model还应该具有一些静态方法用来查找实例,修改实例等,因此该Model还要有一个用于保存模型实例的容器,也就是一个数组或者对象。

 1 Model.extend({
 2     records: {}, //保存实例
 3     find: function(id) {
 4 
 5     },
 6     exists: function(id) {
 7 
 8     },
 9     ...
10 });

至此,一个大致的ORM构建思路就算是完成了,具体的代码还需要不断的添加完成。

原文地址:https://www.cnblogs.com/moyiqing/p/orm.html