db4o的使用问题-一个环状引用导致的对象储存重复--对象的属性是引用其他对象,如果这个引用对象变化了,db4o也认为对象发生了改变,就储存两次??

大家好,我在学习使用db4o做一个餐费管理小系统时,当new Purchase,new Meal后,导致Diner,Account出现重复储存的问题,请兄弟姐妹指教。

共有5个class:
其中使用了List集合类(这个可能是导致问题的主要原因,db4o说Collection作为一个新的对象???)
测试程序使用Meal做入口,new Meal,new Purchase
只保存db.set(Meal);


Meal(purchaseList)---Purchase---Diner----Account----Desposit.
其中Account的purchaseList又包含Purchase。 形成一个对象环状引用。

测试时,先new Diner,new Account;
第一轮测试 Purchase,Meal时,Diner,Account存储没问题,没有重复。

第二轮测试,new Purchase,new Meal时,Diner,Account成倍了,第二次的Account余额不一样;Diner指向的Account也不一样。。

莫非对象的属性是引用其他对象,如果这个引用对象变化了,db4o也认为对象发生了改变,就储存两次??


Meal{
private double balance; //可用余额=despositAmount-purchaseAmount--每次统计
private double purchaseAmount; //购买支付总额--每次统计
private double despositAmount; //存款总额--每次统计
private double initPurchaseAmt; //初始欠费
private double initDespositAmt; //初始存款
private List purchaseList; //购买明细--存放历史明细
private List depositList; //存款明细-交款--存放历史明细
}
Purchase{
private String desc;

private double price;

private Date dateTime;

private int buyingType;

// 参与支付的人员
private List dinerList;
}
Diner{
private String name;
private String comment;
private String phone;
private Account account; //用餐者账户
}
Account{
private double balance; //可用余额=despositAmount-purchaseAmount--每次统计
private double purchaseAmount; //购买支付总额--每次统计
private double despositAmount; //存款总额--每次统计
private double initPurchaseAmt; //初始欠费
private double initDespositAmt; //初始存款
private List purchaseList; //购买明细--存放历史明细
private List depositList; //存款明细-交款--存放历史明细
}
Desposit{
private double amount;
private Date dateTime;
private String desc;
}

请banq大哥指点。

一个Account预包含消费明细purchaseList,是否应该指向Purchase? 还是另外clone Purchase?生成特殊PurchaseItem对象?

另外关于 对象环状引用,如何使对象的属性发生变化而不使db4o认为是一个新的对象产生.

先自己顶下。

我的测试代码是这样的:

public void testCalculateMeal_case2() {
// 测试数据初始化
Account aGuolt = new Account(0.0, 0.0);
Diner guolt = new Diner("Guolt", "GuoLitao", "83737139", aGuolt);
Account aDB = new Account(0.0, 14.0);
Diner db = new Diner("db", "chendb", "7138", aDB);
Account aHjj = new Account(0.0, 79.0);
Diner Hjj = new Diner("hjj", "huangjj", "7139", aHjj);
Account aTanlz = new Account(0.0, 70.0);
Diner tlz = new Diner("tlz", "tanlz", "7131", aTanlz);
Account aSyf = new Account(78.6, 0.0);
Diner syf = new Diner("syf", "shiyf", "7136", aSyf);
Account aWsj = new Account(0, 41.0);
Diner wsj = new Diner("wsj", "wangsj", "7136", aWsj);
// ------------------------------------
Date date1 = new Date();
Date date2 = null;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMDD-HH:MM");
try {
date2 = dateFormat.parse("20080512-12:00");
log.debug("dateFormat: " + date2.toLocaleString());
} catch (ParseException e1) {
e1.printStackTrace();
}
List dinerList1 = new ArrayList();
List purchaseList1 = new ArrayList();
dinerList1.add(guolt);
dinerList1.add(db);
dinerList1.add(tlz);
dinerList1.add(syf);
dinerList1.add(Hjj);
dinerList1.add(wsj);

Purchase pur1 = new Purchase("5-12z Fish Meal", 25.80, date2,
BuyingType.PER, dinerList1);
Purchase pur2 = new Purchase("5-12w basss", 29.50, date2,
BuyingType.PER, dinerList1);
Purchase pur3 = new Purchase("5-13z Crow", 46.90, date2, BuyingType.PER,
dinerList1);
Purchase pur4 = new Purchase("5-13w Dingding", 28.40, date2,
BuyingType.PER, dinerList1);
Purchase pur5 = new Purchase("5-14z gabi", 32.60, date2, BuyingType.PER,
dinerList1);
Purchase pur6 = new Purchase("5-14w gabi", 36.40, date2, BuyingType.PER,
dinerList1);
Purchase pur7 = new Purchase("5-15z gabi", 33.50, date2, BuyingType.PER,
dinerList1);
Purchase pur8 = new Purchase("5-15z gabi", 118.00, date2, BuyingType.PER,
dinerList1);
Purchase pur9 = new Purchase("5-16z gabi", 45.60, date2, BuyingType.PER,
dinerList1);
Purchase pur10 = new Purchase("5-16w gabi", 212.40, date2,
BuyingType.PER, dinerList1);
// 178.63/6=29.771
BookInProxy bookIn = new BookInProxy();

purchaseList1.add(pur1);
purchaseList1.add(pur2);
purchaseList1.add(pur3);

List purchaseList2 = new ArrayList();
purchaseList2.add(pur4);
purchaseList2.add(pur5);
purchaseList2.add(pur6);
purchaseList2.add(pur7);
purchaseList2.add(pur8);
purchaseList2.add(pur9);
purchaseList2.add(pur10);
try {
Date d2 = new Date();
Deposit dpGuolt = new Deposit(100.00, d2, "付阿姨菜钱");// 存款
// bookIn.deposit(guolt, dpGuolt);
// assertEquals(bookIn.getBalance(guolt).getBalance(),103.00, 0);
// assertEquals(bookIn.getBalance(tlz).getBalance(),0.00, 0);
bookIn.bookinPurchaseList(purchaseList1, "08-05-21 午餐",
MealType.LUNCH, date1);
// bookIn.bookinPurchaseList(purchaseList1, "08-05-21
// 午餐",MealType.LUNCH, date1);
//why 两次bookin就会生成两次Purchase,Diner,Account ???
bookIn.bookinPurchaseList(purchaseList2, "08-05-24 午餐",
MealType.LUNCH, date1);
// assertEquals(bookIn.getBalance(guolt).getBalance(),81.59, 0);
// assertEquals(bookIn.getBalance(syf).getBalance(),00.00, 0);
Deposit dpdb = new Deposit(200.00, d2, "付阿姨工资");
// bookIn.deposit(db, dpdb);
// assertEquals(bookIn.getBalance(db).getBalance(),178.59, 0);

Deposit dptlz = new Deposit(100.00, d2, "付阿工资均付");

// bookIn.deposit(guolt, dpGuolt);
// bookIn.deposit(tlz, dptlz);
// 查询余额
log.info("Guolt balance: " + bookIn.getBalance(guolt).getBalance());
log.info("tlz balance: " + bookIn.getBalance(tlz).getBalance());
log.info("db balance: " + bookIn.getBalance(db).getBalance());
log.info("syf balance: " + bookIn.getBalance(syf).getBalance());
log.info("hjj balance: " + bookIn.getBalance(Hjj).getBalance());
log.info("wsj balance: " + bookIn.getBalance(wsj).getBalance());

//
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

第一次调用:

bookIn.bookinPurchaseList(purchaseList1, "08-05-21 午餐",
MealType.LUNCH, date1);
Diner,Account,Purchase,Meal对象等等都储存正常;

随后的第二此调用:

bookIn.bookinPurchaseList(purchaseList2, "08-05-24 午餐",
MealType.LUNCH, date1);
Diner对象加倍;Account也加倍,Account的balance分别是两次的结果;

Purchase也是3+ 10 变成13个了。

如果真的是两个Meal不同,导致两次调用的Purchase也不同,因为Purchase 引用了Diner, Diner引用了Account,Account又反过来引用了Purchase.

请大家赐教!!!

经历了近3周的反复,由于一开始,对象间更新关联关于复杂,导致set时对象重复存放。究其原因是,对象的关系设计混乱,set时犹如一大串珠子,没有抓住主线。

总结一下:

1. 时刻注意内存中的对象和数据库中的对象是否保持一致。

2. 对象间引用不要过多,避免环状引用。这点在初次设计class时,时常犯的错误,一直想这样关联起来才方便。其实对象间关系越简单越好。

3. 注意对象的List集合属性,在存储是,如果没有自动存入,不妨试试专门对此属性进行set,毕竟List也是个对象?? 我目前是这样解决的。

项目的源代码:tableB2.rar


[该贴被gltbeyond于2008-06-04 19:14修改过]
attachment:


tableB2.rar