Morphia官方文档翻译(一)Quick Tour
原文链接:https://mongodb.github.io/morphia/1.2/getting-started/quick-tour/
快速指南
Morphia封装了MongoDB Java driver,所以熟悉driver会有所帮助。Morphia 已经尽了最大努力去从driver中抽象出来,但是如果遇到疑惑不解的问题,请同时参考java driver文档。
以下代码片段来自theQuickTour.java,点击获取 Morphia source。
设置Morphia
下面的例子展示了如何创建Morphia实例。使用该实例,你可以对Morphia如何进行entities映射和提交查询做配置。
final Morphia morphia = new Morphia();
// tell Morphia where to find your classes
// can be called multiple times with different packages or classes
morphia.mapPackage("org.mongodb.morphia.example");
// create the Datastore connecting to the default port on the local host
final Datastore datastore = morphia.createDatastore(new MongoClient(), "morphia_example");
datastore.ensureIndexes();
这段代码创建了我们例子程序将用到的Morphia实例。Morphia类可以配置Mapper和一些系统范围的选项,也负责创建Datastore。Datastore有两个参数:MongoClient和数据库的名字。通过创建不同的Datastore,我们可以只配置Morphia一次,但连接不同的数据库,实际应用中,这种情况不常见,但有可能存在。
被我们跳过的第二行,值得更进一步说明。在这个例子中,我们告诉Morphia搜索指定的包,找到每一个@Entity(后续说明这个注解)注解的类,进一步发现要映射的元数据(metadata )。有几种不同的映射并且可以多次调用,以便覆盖你所有的entities。
映射选项(Mapping Options)
创建Morphia实例后,可以通过MappingOptions类配置映射选项。虽然在创建Morphia实例的时候也可以指定Mapper,但大部分人会使用默认的mapper。不管哪种情况,都可以通过Morphia实例的getMapper()方法获取Mapper。最常用的两个选项是storeEmpties和storeNulls。默认情况下,Morphia不会存储空List或Map,也不会存储null值到MongoDB上。如果你的应用需要用到empty or null 值,需设置相应的选项为true。还有一些其他的配置选项,在这儿不会提到。
映射类(Mapping Classes)
Morphia处理你的类有两种方式:上层的entities或嵌入式的entities(as top level entities or embedded in others)。任何@Entity注解标注的类都会被视为上层entities,直接对应MongoDB中的collection的document。任何@Entity注解标注的类必须有一个@Id注解的字段,对应MongoDB的document的_id。@Embedded表示这个类是嵌入式的文档,不要求有@Id注解的字段。
@Entity("employees")
@Indexes( @Index(value = "salary", fields = @Field("salary")))
class Employee {
@Id
private ObjectId id;
private String name;
@Reference
private Employee manager;
@Reference
private List<Employee> directReports;
@Property("wage")
private Double salary;}
@Entity注解里有个"employees",默认情况下Morphia使用类名作集合名,如果传入了字符串,就会使用这个字符串作集合名。更多注解的细节请查阅annotations guide
@Indexes注解列出了Morphia将创建哪些索引,在这个例子中,我们在字段salary上定义了一个名为salary的索引,默认升序。更多信息在这里
我们标记了id字段为我们的主键(document的_id字段),ID的类型为Java driver的ObjectId类型。ID可以是任何类型,但通常是ObjectId或Long类型。需要指出的是,Morphia将尝试拷贝每一个字段到数据库中,而不是transient and static。
@Property注解是一个可选项,如果不使用这个注解,Morphia会使用Java字段名做document的字段名,使用@Property注解可以指定document的字段名。
@Reference告诉Morphia这个字段引用了另外的Morphia mapped entities。在这种情况下,Morphia会按照MongoDB中DBRef 的方式存储,其实就是集合名和键值。这些引用的entities必须已经存储了或者至少已分配了ID,否则Morphia会抛出异常。
存储数据(Saving Data)
像平常使用Java对象一样使用:
final Employee elmer = new Employee("Elmer Fudd", 50000.0);
datastore.save(elmer);
更进一步,定义一些关系并存储:
final Employee daffy = new Employee("Daffy Duck", 40000.0);
datastore.save(daffy);
final Employee pepe = new Employee("Pepé Le Pew", 25000.0);
datastore.save(pepe);
elmer.getDirectReports().add(daffy);
elmer.getDirectReports().add(pepe);
datastore.save(elmer);
正如你所看到的,我们只需要创建和保存其他Employees,然后就可以添加他们到direct reports链表并保存。Morphia负责保存Daffy and Pepé相关的keys到Elmer’s document。更新MongoDB中的数据就像更新你的Java对象一样简单,最后记着调用datastore.save()。对于大量的更新(比如每个人都晋升了),这不是最有效的更新方式。在不拉取每个document的前提下直接更新数据库的数据是有可能的,转换成Java对象,更新,转换回document,然后写入MongoDB.在展示这个机制之前,先要看看怎么查询。
查询(Querying)
Morphia尝试使你的查询尽可能类型安全。转换你数据的所有细节都直接被Morphia处理了,几乎没有什么额外的操作需要你来进行。
final Query<Employee> query = datastore.createQuery(Employee.class);
final List<Employee> employees = query.asList();
这是一个简单的Morphia查询。我们让Datastore创建一个Employee类型的查询,把查到Employee存到List中。对于很大的查询结果,这很可能导致内存不足。在这个简单的例子中使用了asList(),但实际上,fetch()是更合适的选择。大多数查询都会以某种方式过滤数据,有两种方式实现:
underpaid = datastore.createQuery(Employee.class)
.field("salary")
.lessThanOrEq(30000) .asList();
field()方法用来过滤字段并且返回一个接口的实例,这个接口含有一组用于构建查询的方法。这种方式是有益的,编译时检查是必要的。这种查询构建的方式对于避免javac因缺失方法失败和辅助IDE的自动完成都很有用。
另一种使用filter()方法的途径比field()更加自由和简洁。我们可以直接嵌入操作符到查询字符串中。虽然这种方式没有那么繁冗,它确实放了更多的东西到字符串中来验证并有可能出错:
List<Employee> underpaid = datastore.createQuery(Employee.class)
.filter("salary <=", 30000)
.asList();
更新(Updates)
掌握了查询之后,我们可以回到in-database更新的问题。这类更新包含两个组件:一个查询,一系列更新操作。在这个例子中,我们找出所有领取薪酬的员工,给他们加薪10000。第一步是创建查询找出领取薪酬的员工,这段代码我们之前已见到过:
final Query<Employee> underPaidQuery = datastore.createQuery(Employee.class)
.filter("salary <=", 30000);
To define how we want to update the documents matched by this query, we create an UpdateOperations instance:
为了定义我们如何更新documents,我们先创建一个UpdateOperations 实例:
final UpdateOperations<Employee> updateOperations = datastore.createUpdateOperations(Employee.class)
.inc("salary", 10000);
这个类有很多种操作,但在这个例子中,我们只更新salary字段(增加10000),用到了$inc
operator。最后一步:
final UpdateResults results = datastore.update(underPaidQuery, updateOperations);
这行代码执行了数据库内的update,没有拉取documents。UpdateResults实例返回一系列更新操作的统计数据。
删除(Removes)
final Query<Employee> overPaidQuery = datastore.createQuery(Employee.class)
.filter("salary >", 100000);
datastore.delete(overPaidQuery);
delete()有一些其他的用法,但这就是最普通的用法。如果你手上已经有了一个对象,有一个delete可以取得引用并删除它。更多信息请参考javadoc