论坛首页 Java企业应用论坛

在Java 实现真正的富领域Model层

浏览 20912 次
精华帖 (10) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-08-08  
delphixp 写道
想法不错。。。在 基类 Model 中设计了一个小型 DSL。。

Query Interface (也就是你提到的这个DSL)是精华 呵呵
0 请登录后投票
   发表时间:2012-08-08  
标题述语很复杂, 表示不理解.
0 请登录后投票
   发表时间:2012-08-08  
nakupanda 写道
标题述语很复杂, 表示不理解.

本质就是舍去dao层,部分取代service.model 自我操作,而不是一个简单的pojo.
0 请登录后投票
   发表时间:2012-08-08  
allwefantasy 写道

 

查询接口

 

为了高效,规范化的操作数据库, 框架提供了众多的查询方法. 每个查询方法允许你传递参数执行特定的查询而不需要你写令人烦躁的sql语句。

方法列表:

  • where
  • select
  • group
  • order
  • limit
  • offset
  • joins
  • from

以后我们会继续完善。添加更多方法,譬如 lock,having等。

从这些关键字可以看出,这些方法基本是以Sql关键字为基础的。所有这些方法最终返回的是JPQL对象(ServiceFramework内部组装sql语句的一个类)。

1.1 根据ID获得对象

 

Tag.findById(10)
//或者
Tag.find(10)
 

1.2 根据多个ID获取

 

Tag.find(list(1,2,,4,5))
 

1.3 条件查询

 

Tag.where("id=:id",map("id",7)).fetch();
 

map 是一个创建Map的一个便利方法。

你也可以使用一个更复杂的例子:

 

Tag.where("tag_synonym=:tag_synonym",map("tag_synonym",tag_synonym));
 

还记得之前提到的,对象关联关系的建立,可以方便框架进行一些对象化的操作。在Tag中tag_synonym是一个对象属性,你可以直接在where中使用该属性。 他会转为为类似:

 

select * from Tag where tag_synonym_id=? 
 

因为对象关联模型告诉了系统那个是外键。这不会带来任何性能方面的损耗。

1.4 order

 

Tag.order("id desc")
 

或者

 

Tag.order("id desc,name asc")
 

1.5 joins

joins 语法也是对象化的,这也得益于我们之前简单的模型关系声明。你所操作的就是相应的模型属性。不管简单属性还是对象属性。

 

Tag.joins("tag_synonym").fetch();
 

那么 tag对象的tag_synonym 属性会自动得到填充。这不会有n+1问题。因为一条SQL语句就搞定了

你也可以join多个属性

 

Tag.joins("tag_synonym left join  tag_groups left join blog_tags").fetch();
 

当然,对于互联网应用,这么多join毫无疑问会拖垮你的数据库。我们只是举个例子,你不应该这么做。

1.6 offset,limit

 

Tag.offset(10).limit(15);
//这相当于
select * from Tag limit 10,15;
 

1.7 select

这通常用于你不想获取所有的字段的场合

 

 List<Object[]> results =Tag.select("name").fetch();
 

这通常返回是一个数组。当然,如果你想让它填充进一个模型也是可以的。

 

 List<Tag> results =Tag.select("new Tag(name)").fetch();
 

需要注意的是,你需要在Tag填充一个相应的构造方法。希望不久就能去掉这个限制。嗯,应该尽力去掉。

1.8 group 说实话,真不应该提供这个,性能杀手。不过还是提供了….

 

Tag.where("id>10").group("name").fetch();
 

Name_Scope

假设tag需要审核。只有审核通过的才应该被查询出来。如果每次查询的时候都要加这个条件岂不是 太麻烦?我们可以定义一个方法:

 

@Entity
public class Tag extends Model {
    public static JPQL active(){
      return where("status=1");
    }
}
 

之后你就可以这么用了

 

Tag.active().where("id>10").join("tag_groups").offset(0).limit(15).fetch();
 

模型方法

一旦你定义了模型类,那么该模型类会自动拥有众多的方法。一些静态方法:

    Tag.create(map)
    Tag.deleteAll()
    Tag.count()
    Tag.count(String query, Object... params)
    Tag.findAll()
    Tag.findById(Object id)
    Tag.all() 
    Tag.delete(String query, Object... params)

    Tag.where(String whereCondition, Object... params)
    Tag.join(String join)
    Tag.order(String order)
    Tag.offset(int offset)
    Tag.limit(int limit)
    Tag.select(String select)

一些实例方法

    tag.save()
    tag.valid()
    tag.update()
    tag.refresh()
    tag.delete()

框架还会为你生成很多你看不见的"模型实例方法"。你需要特定语法去调用他。这里使用"m" 方法。 这主要针对关联关系。 对于类似这种申明:

 

@ManyToMany
private List<Tag> tags = new ArrayList<Tag>();
 

那么你能获得tags方法。

 

tagGroup.m("tags",Tag.create(map("name","jack")));
 

这段代码的含义是,调用tags方法,该方法接受tag实例作为参数。实际上tags方法等价于下面的方法(只是你看不到这个方法,但是能通过"m”调用他)

 

public TagGroup tags(Tag tag){
       this.tags.add(tag);
       tag.getTag_groups().add(this);
       return this;
  }
 

配置了关联关系的字段都会自动生成一个同名的方法,通过调用他们,会自动将对象之间的关联关系设置好,从而可以直接使用包括级联保存等ORM特性。

 

Validator

框架应该提供一个声明式的validator语法。

 

@Validate
    private final static Map $name = map(
         presence, map("message", "{}字段不能为空"),
         uniqueness, map("message", "{}字段不能重复")
    );
 

验证器:

  • presence 值不能为null或者空
  • uniqueness 值具有唯一性
  • numericality 是数字,且可以设置范围
  • format 正则
  • associated 关联对象验证
  • length 长度校验

 

你可以显式调用一个模型的valid()方法。你也可以直接调用save()方法。该方法返回boolean.false代表没有通过验证。 验证结果你可以通过直接使用模型的validateResults属性获取。

 

if(!tag.save()){
   render(HTTP_400,tag.validateResults);
 }

 //或者

 if(tag.valid()){
   tag.save();
 }
 

对于save方法,你也可以跳过验证

tag.save(false)

参数 false 表示不需要验证就进行保存。

1.1 prensence

 

@Validate
private final static Map $name = map(presence, map("message", "{}字段不能为空"));
 

1.2 uniqueness

 

@Validate
private final static Map $name = map(uniqueness, map("message", ""));
 

1.3 numericality

 

@Validate
private final static Map $id = map(numericality, map("greater_than",10,"message":""));
 

拥有的选项为:

  • greater_than
  • greater_than_or_equal_to
  • equal_to
  • less_than
  • less_than_or_equal_to
  • odd
  • even

1.4 length

 

@Validate
private final static Map $name = map(length, map("minimum",10));
 

拥有的选项:

  • minimum
  • maximum
  • too_short
  • too_long


链式的操作很方便,不过在java中用类方法应该会有多线程的问题;

当同时两个线程调用Tag.where(),Tag.order()的时候应该会出现问题;

我比较好奇这个你是怎么解决的;

  • 大小: 759.6 KB
0 请登录后投票
   发表时间:2012-08-09  
bnmcvzx 写道
allwefantasy 写道

 

查询接口

 

为了高效,规范化的操作数据库, 框架提供了众多的查询方法. 每个查询方法允许你传递参数执行特定的查询而不需要你写令人烦躁的sql语句。

方法列表:

  • where
  • select
  • group
  • order
  • limit
  • offset
  • joins
  • from

以后我们会继续完善。添加更多方法,譬如 lock,having等。

从这些关键字可以看出,这些方法基本是以Sql关键字为基础的。所有这些方法最终返回的是JPQL对象(ServiceFramework内部组装sql语句的一个类)。

1.1 根据ID获得对象

 

Tag.findById(10)
//或者
Tag.find(10)
 

1.2 根据多个ID获取

 

Tag.find(list(1,2,,4,5))
 

1.3 条件查询

 

Tag.where("id=:id",map("id",7)).fetch();
 

map 是一个创建Map的一个便利方法。

你也可以使用一个更复杂的例子:

 

Tag.where("tag_synonym=:tag_synonym",map("tag_synonym",tag_synonym));
 

还记得之前提到的,对象关联关系的建立,可以方便框架进行一些对象化的操作。在Tag中tag_synonym是一个对象属性,你可以直接在where中使用该属性。 他会转为为类似:

 

select * from Tag where tag_synonym_id=? 
 

因为对象关联模型告诉了系统那个是外键。这不会带来任何性能方面的损耗。

1.4 order

 

Tag.order("id desc")
 

或者

 

Tag.order("id desc,name asc")
 

1.5 joins

joins 语法也是对象化的,这也得益于我们之前简单的模型关系声明。你所操作的就是相应的模型属性。不管简单属性还是对象属性。

 

Tag.joins("tag_synonym").fetch();
 

那么 tag对象的tag_synonym 属性会自动得到填充。这不会有n+1问题。因为一条SQL语句就搞定了

你也可以join多个属性

 

Tag.joins("tag_synonym left join  tag_groups left join blog_tags").fetch();
 

当然,对于互联网应用,这么多join毫无疑问会拖垮你的数据库。我们只是举个例子,你不应该这么做。

1.6 offset,limit

 

Tag.offset(10).limit(15);
//这相当于
select * from Tag limit 10,15;
 

1.7 select

这通常用于你不想获取所有的字段的场合

 

 List<Object[]> results =Tag.select("name").fetch();
 

这通常返回是一个数组。当然,如果你想让它填充进一个模型也是可以的。

 

 List<Tag> results =Tag.select("new Tag(name)").fetch();
 

需要注意的是,你需要在Tag填充一个相应的构造方法。希望不久就能去掉这个限制。嗯,应该尽力去掉。

1.8 group 说实话,真不应该提供这个,性能杀手。不过还是提供了….

 

Tag.where("id>10").group("name").fetch();
 

Name_Scope

假设tag需要审核。只有审核通过的才应该被查询出来。如果每次查询的时候都要加这个条件岂不是 太麻烦?我们可以定义一个方法:

 

@Entity
public class Tag extends Model {
    public static JPQL active(){
      return where("status=1");
    }
}
 

之后你就可以这么用了

 

Tag.active().where("id>10").join("tag_groups").offset(0).limit(15).fetch();
 

模型方法

一旦你定义了模型类,那么该模型类会自动拥有众多的方法。一些静态方法:

    Tag.create(map)
    Tag.deleteAll()
    Tag.count()
    Tag.count(String query, Object... params)
    Tag.findAll()
    Tag.findById(Object id)
    Tag.all() 
    Tag.delete(String query, Object... params)

    Tag.where(String whereCondition, Object... params)
    Tag.join(String join)
    Tag.order(String order)
    Tag.offset(int offset)
    Tag.limit(int limit)
    Tag.select(String select)

一些实例方法

    tag.save()
    tag.valid()
    tag.update()
    tag.refresh()
    tag.delete()

框架还会为你生成很多你看不见的"模型实例方法"。你需要特定语法去调用他。这里使用"m" 方法。 这主要针对关联关系。 对于类似这种申明:

 

@ManyToMany
private List<Tag> tags = new ArrayList<Tag>();
 

那么你能获得tags方法。

 

tagGroup.m("tags",Tag.create(map("name","jack")));
 

这段代码的含义是,调用tags方法,该方法接受tag实例作为参数。实际上tags方法等价于下面的方法(只是你看不到这个方法,但是能通过"m”调用他)

 

public TagGroup tags(Tag tag){
       this.tags.add(tag);
       tag.getTag_groups().add(this);
       return this;
  }
 

配置了关联关系的字段都会自动生成一个同名的方法,通过调用他们,会自动将对象之间的关联关系设置好,从而可以直接使用包括级联保存等ORM特性。

 

Validator

框架应该提供一个声明式的validator语法。

 

@Validate
    private final static Map $name = map(
         presence, map("message", "{}字段不能为空"),
         uniqueness, map("message", "{}字段不能重复")
    );
 

验证器:

  • presence 值不能为null或者空
  • uniqueness 值具有唯一性
  • numericality 是数字,且可以设置范围
  • format 正则
  • associated 关联对象验证
  • length 长度校验

 

你可以显式调用一个模型的valid()方法。你也可以直接调用save()方法。该方法返回boolean.false代表没有通过验证。 验证结果你可以通过直接使用模型的validateResults属性获取。

 

if(!tag.save()){
   render(HTTP_400,tag.validateResults);
 }

 //或者

 if(tag.valid()){
   tag.save();
 }
 

对于save方法,你也可以跳过验证

tag.save(false)

参数 false 表示不需要验证就进行保存。

1.1 prensence

 

@Validate
private final static Map $name = map(presence, map("message", "{}字段不能为空"));
 

1.2 uniqueness

 

@Validate
private final static Map $name = map(uniqueness, map("message", ""));
 

1.3 numericality

 

@Validate
private final static Map $id = map(numericality, map("greater_than",10,"message":""));
 

拥有的选项为:

  • greater_than
  • greater_than_or_equal_to
  • equal_to
  • less_than
  • less_than_or_equal_to
  • odd
  • even

1.4 length

 

@Validate
private final static Map $name = map(length, map("minimum",10));
 

拥有的选项:

  • minimum
  • maximum
  • too_short
  • too_long


链式的操作很方便,不过在java中用类方法应该会有多线程的问题;

当同时两个线程调用Tag.where(),Tag.order()的时候应该会出现问题;

我比较好奇这个你是怎么解决的;

 

当你调用 Tag.where() 其实是返回一个 JPQL对象

 

Tag.where().order().fetch();

//实际执行的语句序列

JPQL jpql = new JPQL();
jpql.where().order().fetch();
 

 所以并没有多线程的问题。

 

 

0 请登录后投票
   发表时间:2012-08-09   最后修改:2012-08-09
不错的东西,就是和标题有点不搭嘎

领域是种概念,是种建模方法,而非狭义的一个layer
0 请登录后投票
   发表时间:2012-08-09  
qamer 写道
不错的东西,就是和标题有点不搭嘎

领域是种概念,是种建模方法,而非狭义的一个layer

嗯 主要是希望大家能够关注下...哈哈 我觉得目前这种实现可以做到非常的敏捷,尤其是代码量,是以前不可想象的。并且没有太多魔法就实现了。
0 请登录后投票
   发表时间:2012-08-09  
我反而觉得DAO+POJO结构更清晰
0 请登录后投票
   发表时间:2012-08-09  
nakupanda 写道
我反而觉得DAO+POJO结构更清晰

关键在于,
1. dao+pojo太多重复代码。一上来就定义大量pojo类,然后定义相应的dao,不同项目你的通用dao类可能需要拷贝来拷贝去,并且每个人都可能会有自己喜欢的dao实现。
2. hibernate 配置过于繁杂,要么通过hibernate自己的配置文件,要么通过spring提供的胶水配置。一票的配置,你不找template,基本上没人能够配置的下来。
3 只有代码越少越集中,才能更清晰,更容易维护

这些都是充血模型带来的好处。简单一个Model类,就把pojo,dao,以及部分service都给处理了。而且责任也更加清晰。比如,我要取出tag所有status为1的记录。我直接向该模型类要,不是更合理吗?

还有一点需要指出的,充血模型你唯一需要做的就是一个关联申明,然后所有的方法和属性都给你提供了。你可以参看主题帖的第一篇,四个模型类,有三个模型类里面的代码就一行和一个最最简单的注解。
0 请登录后投票
   发表时间:2012-08-09  
用过rails就知道这种模式的方便,易用。我也一直在找这方面的框架,如果有这样的项目或者你是项目发起人,我愿意参与进去,贡献代码。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics