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

08-05-30 gltbeyond
    

大家好,我在学习使用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;

}

    

gltbeyond
2008-05-30 14:35

请banq大哥指点。

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

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

gltbeyond
2008-05-30 15:05

先自己顶下。

我的测试代码是这样的:

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);

gltbeyond
2008-05-30 15:05

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.

请大家赐教!!!

gltbeyond
2008-06-04 19:13

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

总结一下:

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

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

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

项目的源代码:tableB2.rar

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


tableB2.rar