Skip to content

ServiceFramework MongoDB DataMapper Support

allwefantasy edited this page Oct 24, 2012 · 8 revisions

##ServiceFramework MongoDB Support

注: 文档中的具体类来自com.example.document ,如果你想看类的完整样子,可以移步到 项目中查看那。

这次我们的model类不需要任何Annotation和配置文件(当然mongodb的链接配置还是需要的)。完全使用声明式语法!

####mongodb 使用配置:

development:
    datasources:
        mysql:
           host: 127.0.0.1
           port: 3306
           database: wow
           username: mysql
           password: ****
           disable: false
        mongodb:
           host: 127.0.0.1
           port: 27017
           database: data_center
           disable: false
        redis:
            host: 127.0.0.1
            port: 6379
            disable: true`

上面就是mongodb所有的被指选项。 你可以通过disable来关闭活着开启mongodb. 同理redis 和 mysql 都可以通过disable 选项进行开启活着关闭。

####mongodb 建模

mongodb 因为是schema free style的,存储结构是BSON结构,这就意味着mongodb的类关联有两种,分别为embedded 和 related. 我们一一举例(例子只是为了说明用法)

先说传统的related 模式,就是不同的model 对应不同的表。

public class Person extends Document {
    //在静态代码块里做声明式配置。
    static {
        //说明mongodb中的表名称为persons
        storeIn("persons");
        //和Address 的多对一关系。你只要告诉关联的类名和外键id即可。
        hasMany("addresses", new Options(map(
                Options.n_kclass, Address.class,
                Options.n_foreignKey, "person_id"
        )));
        //和IdCard的一对一关系。你依然需要提供关联的类名和外键id名称
        hasOne("idcard", new Options(map(
                Options.n_kclass, IdCard.class,
                Options.n_foreignKey, "person_id"
        )));
    }

    //你只要声明这个方法,方法名称对应hasMany的那个名字
    public Association addresses() {
        throw new AutoGeneration();
    }
    //你只要声明这个方法,方法名称对应hasOne的哪个名字
    public Association idcard() {
        throw new AutoGeneration();
    }

    //定义属性
    private String name;
    private Integer bodyLength;


    //这些用IDE自动生成吧。记住生成后就不要动他们了。因为框架会自动对这些方法增强
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getBodyLength() {
        return bodyLength;
    }

    public void setBodyLength(Integer bodyLength) {
        this.bodyLength = bodyLength;
    }
}


public class Address extends Document {
    static {
         
        storeIn("addresses");

        belongsTo("person", new Options(
                map(
                        Options.n_kclass, Person.class,
                        Options.n_foreignKey, "person_id"
                )

        ));
    }

    public Association person() {
        throw new AutoGeneration();
    }


    private String location;

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }
}

大部分功能使用已经写在了代码注释中了。 这次我们发现比 传统的ORM model略微繁琐点。其实去掉get/set也没多少。然后就是属性定义和关联关系声明了。属性你其实可以完全不定义,没有关系。但是如果你需要访问属性的话,建议还是定义一下,这样方方便IDE生成get/set方法,生成get/set方法有啥好处呢?就是方便你访问属性贝。

上面就把所有的配置好了。 接着开始讲解使用方式。

新建一个Person 实例并且存储它。

Person person = Person.create(map(
                "_id", 100,
                "name", "google",
                "bodyLength", 10
        ));

person.save();
                

现在添加一个新的Address给我们刚才存储的人。

 person.addresses().build(map("_id", 77, "location", "天国的世界")).save();

那如果我们根据name 查询那些人呢?

List<Person> persons = Person.where(map("name","google")).fetch();

根据ID查询:

Person person = Person.findById(100);
//你也可以一次查询多个id
List<Person> persons = Person.find(list(100,1000));

如果我已经有person对象,想找到这个人的id为77的地址怎么办?

person.addresses().filter().findById(77);
//其实你还可以使用where条件语句,比如
person.addresses().filter().where(map("_id",77)).singleFetch();

是不是觉得查询挺爽的。

如果我要删除呢?

person.remove();//就这么一句话

好了,我们现在看看embedded 文档是怎么样的。

public class Blog extends Document {
    static {
        storeIn("blogs");
        //和related 唯一的区别就是使用hasManyEmbedded而不是hasMany
        hasManyEmbedded("articles", new Options(map(
                Options.n_kclass, Article.class
        )));

    }

    public AssociationEmbedded articles() {
        throw new AutoGeneration();
    }
    
    
    //属性啦
    private String userName;
    private String blogTitle;

    //properties and their access methods
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getBlogTitle() {
        return blogTitle;
    }

    public void setBlogTitle(String blogTitle) {
        this.blogTitle = blogTitle;
    }

  

}


ublic class Article extends Document {
    static {
        storeIn("articles");
        belongsToEmbedded("blog", new Options(map(
                Options.n_kclass, Blog.class
        )));
    }

    public AssociationEmbedded blog() {
        throw new AutoGeneration();
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String title;
    public String body;
}

我们直接看看使用吧。

首先假设客户端传来的数据类似:

  Map blogMap = map(
                "_id", 100,
                "userName", "jack",
                "blogTitle", "this is a test blog",
                "articles", list(
                map(

                        "title", "article",
                        "body", "article body"
                ),
                map(

                        "title", "article1",
                        "body", "article body1"
                )
        )
        );

我们看到这事比较复杂的嵌套结构。那么如何保存到mongodb呢?

 Blog blog = Blog.create(blogMap);
 blog.save();
 blog = Blog.findById(100);
 List<Article> articles = blog.articles().find();

用法上和前面完全一样。

如何删除呢?

 List<Article> articles = blog.articles().find();
 articles.get(0).remove();//这样就把子元素删除掉啦。

记住 embedded 如果删除最外层的类,会把所有的子元素删除掉。因为毕竟他们是一条记录,其实。