DB4O学习(六)—has-an关联
1.总的类图:
2.java类
public static void main(String[] args) { ObjectContainer db = null; try{ db = Db4o.openFile("person.yap"); Address a1 = new Address("1 First Street", "San Jose", "USA"); Customer cu1 = new Customer("Gary", "408 123 4567", "gary@example.net", a1); db.set(cu1); }finally{ if(db!=null){ db.close(); } } }
In fact, when you store one object, by default the database will also store the objects that
can be reached by navigating the in-memory object graph starting from that object.
数据库中自动存储:
AbstractPerson,Address,Customer,Zipcode
也可以明确先存address,后存customer,但这样不必要:
db.set(a1); db.set(cu1);
注意:
■Caution This is true if the associated objects are stored within the same transaction, which is to say
before the ObjectContainer is closed. If the Address object is stored explicitly in one transaction, and the
Customer object is stored within another, then the database cannot automatically associate the stored
Address with the Address belonging to the Customer. As a result, an additional Address object, with the
same field values but with a different OID, will be stored. The correct way to deal with this would be to retrieve
the previously stored Address and associate that explicitly with the Customer before storing the Customer.
3.查询
Retrieving a structured object is just as simple as storing it. Again, you just need to retrieve
the top-level object, and associated objects will by default be retrieved along with it.
(1)只要查询顶层的类就行了。
Customer customerExample = new Customer("Gary", null, null, new Address(null,null,null)); ObjectSet results = db.get(customerExample); while (results.hasNext()) { Customer customer = (Customer)results.next(); System.out.println(customer); System.out.println(customer.getAddress()); }
Note that this single query has returned both objects. The same thing can be done with a
native query:
一个简单的查询就返回所有的objects,也可以用NQ查询:
// execute query List customers = db.query(new Predicate<Customer>() { public boolean match(Customer cust) { return cust.getName().equals("Gary"); } }); // list results for (Customer customer : customers ) { System.out.println(customer); System.out.println(customer.getAddress()); }
(2)查询地址
List<Address> addresses = db.query(new Predicate<Address>() { public boolean match(Address add) { return add.getStreet().equals("1 First Street"); } });
这里address在代码里并没有与customer关联,所以只能查询自己。
(3)通过address查询customer
List<Customer> customers = db.query(new Predicate<Customer>() { public boolean match(Customer cust) { return cust.getAddress().getStreet().equals("1 First Street"); } });
SODA版本:
Query query = db.query(); query.constrain(Customer.class); query.descend("_address").descend("_street").constrain("1 First Street"); ObjectSet results = query.execute();
4.更新
可以同时更新它的关联对象
List<Customer> customers = db.query(new Predicate<Customer>() { public boolean match(Customer cust) { return cust.getName().equals("Gary"); } }); Customer cu = customers.get(0); // get first returned Customer - should only be one cu.getAddress().setStreet("2 Second Street"); db.set(cu);
虽然更改的是address,但保存仍然通过customer来进行。
如果要通过customer查询更改的结果,必须确保该查询与更新的操作不在同一个事务当中。
需在在更新那个db关闭之后另外查询。因为通过set来保存只有在db关闭之后才真正存入数据库。
但是这样仍然没有更改,若代码改为如下:
cu.getAddress().setStreet("2 Second Street");
db.Set(cu.getAddress());
但是如果单独保存address,则立即更新数据库。
通过顶层对象来更新其他关联对象,会造成性能问题,因此必须单独明确保存才立刻保存。----这是db4o的默认操作。
但可以通过如下设置来实现级联更新:
Db4o.configure().objectClass(Customer.class).cascadeOnUpdate(true);
5.删除
List<Customer> customers = db.query(new Predicate<Customer>() { public boolean match(Customer cust) { return cust.getName().equals("Gary"); } }); Customer cu = customers.get(0); // get first returned Customer - should only be one db.delete(cu);
这里只是删除customer,address并没有级联删除。
可以通过设置来实现级联删除
Db4o.configure().objectClass(Customer.class).cascadeOnDelete(true);
但必须注意address是否有跟其他customer关联。
6.对象的激活
激活状态:从数据库中调入内存中。最小的激活深度是1:即只能访问顶层对象的非对象关联属性。
关联的对象为空,并没有被加载到内存中。默认的激活深度是5。如下设为1:
List<Customer> customers = db.query(new Predicate<Customer>() { public boolean match(Customer cust) { return cust.getName().equals("Gary"); } }); Customer cu = customers.get(0); // Breakpoint on next line
则address对象为空。
可以通过如下来激活:
db.activate(cu.getAddress(), 1);
7.对象的钝化
如果不再需要该对象,可以将其钝化:
// JAVA
db.deactivate(cu.getAddress(), 1);
则address将被设为空,他的属性被设为默认值。
8.对象的关联等级
// JAVA ZipCode z1 = new ZipCode("CA", "95200", "1234"); ZipCode z2 = new ZipCode("CA", "95200", "5678"); Address a1 = new Address("1 First Street", "San Jose", "USA"); a1.setZipCode(z1); a2.setZipCode(z2); Customer cu1 = new Customer("Gary", "408 123 4567", "gary@example.net", a1); Customer cu2 = new Customer("Mary", "408 101 1001", "mary@example.com", a2); db.set(cu1); db.set(cu2);
深度查询:查询地址的邮编为1234的customer:
QBE版本:
ZipCode zipExample = new ZipCode(null, null, "1234");
Address addressExample = new Address(null,null,null);
addressExample.setZipCode(zipExample);
Customer customerExample = new Customer(null, null, null, addressExample);
ObjectSet results = db.get(customerExample);
while (results.hasNext())
{
Customer customer = (Customer)results.next();
System.out.println(customer);
System.out.println(customer.getAddress());
System.out.println(customer.getAddress().getZipCode());
}
NQ版本:
// JAVA List<Customer> customers = db.query(new Predicate<Customer>() { public boolean match(Customer cust) { return cust.getAddress().getZipCode().getExtension().equals("5678"); } });
SODA版本:
// JAVA Query query = db.query(); query.constrain(Customer.class); Query zipQuery = query.descend("_address").descend("_zipCode"); zipQuery.descend("_extension").constrain("5678"); ObjectSet results = query.execute();
9.双向关联:
需要address里面有对customer的引用:
Customer _customer; ... public Customer getCustomer() { return _customer; } public void setCustomer(Customer value) { _customer = value; }
但要注意维护二者之间的关系:
public Customer(String name, String phoneNumber, String email, Address address) { super(name,phoneNumber,email); _address = address; address.setCustomer(this); }
public void setAddress(Address value) { _address = value; value.setCustomer(this); }
此时,无论保存哪一者,另一方也被保存:
// C# & JAVA Address a1 = new Address("1 First Street", "San Jose", "USA"); Customer cu1 = new Customer("Gary", "408 123 4567", "gary@example.net.com", a1);
db.set(a1);