【问题标题】:Can I temporarily suspend auto-generated ID in ORMLite?我可以在 ORMLite 中暂时暂停自动生成的 ID 吗?
【发布时间】:2011-03-07 06:44:08
【问题描述】:

我在我目前正在编写的一个小应用程序中使用带有 ORMLite 的 Android。该应用程序旨在拥有一个有效的导入/导出功能,为此我使用简单的 XML 框架。在某种程度上,一切都很好。

情况如下:对象A包含一个引用对象B的外键,而对象B是通过外键本身来引用对象C的。导出数据库很棒。导入工作,有一个小警告,即只要所有对象的 ID 是连续的并且从 1 开始,它就可以工作。但是如果数据库是碎片化的,即我在这里和那里删除了一条记录,在我导出数据库之后,我在生成的 XML 结构中有“漏洞”。示例对象可能是:

@DatabaseTable("orders")
public class Order {
    @DatabaseField(generatedId = true)
    private int _id;
    @DatabaseField(columnName="date")
    private Date _date;
    @DatabaseField(columnName="cost")
    private double _cost;
    @DatabaseField(foreign = true, columnName="customer_id")
    private Customer _customer;
    // ... more fields, getters and setters
}

@DatabaseTable("customers")
public class Customer {
    @DatabaseField(generatedId = true);
    private int _id;
    @DatabaseField
    private String _name;
    // ... more fields, getters and setters
}

假设我有一个包含 2 个客户(id 1 和 2)的数据库,它们分别保存从 1 到 5 和 6 到 8 的订单。导出这个然后在干净的数据库中重新导入效果很好。但是,如果我删除客户 1 及其订单并将其导出,则出口商将按原样写出他们的 id,即

<customer id="2">...</customer>

<order id="6">...</order>
<order id="7">...</order>
<order id="8">...</order>
<order id="9">...</order>

等等。当我将数据导入新数据库时,我会首先通过

保存客户对象
custDao.create((Customer)x);

然后他们的每个订单通过

orderDao.create((Order)o);

问题在于 create 函数忽略了提供的 id(不是 0)并且新生成的 customer id 是 1(在一个新的空数据库中)。订单也一样。但是由于他们引用了 id=2 的客户,因此他们之间的联系被破坏了。

所以在这个有点冗长的解释之后,这是我的问题:有没有办法告诉 ORMLite 为 generateId 字段获取提供的值并使用它运行,而不是覆盖它?如果创建函数在表中找到具有相同 ID 的行已经生成任何异常,我会没事的,但会继续保存记录,否则...... 我已经想到了一个解决方法:所有对象都应该可以使用 Comparator 接口按 ID 排序;使用要导入的对象对 ArrayList 进行排序;对于每个对象 - 将假定 id 读入 int, - 使用 dao.create 保存到数据库, - 如果对象的新 id 与假定 id 不同,则通过 dao.updateId 更改它, - 移动到列表中的下一个对象.. . 但这似乎太麻烦且容易出错:如果 create 方法尝试生成一个 id,而您只是将其重新分配给具有 updateId 的先前对象,该怎么办?

我不相信我的情况如此罕见,以前没有人遇到过这种情况。我将不胜感激!

最好的问候, 托多尔

【问题讨论】:

  • 只是想确保您看到我的答案@todor 的更新。

标签: java android sqlite ormlite


【解决方案1】:

ORMLite 支持 allowGeneratedIdInsert=true 选项到 @DatabaseField 注释,允许将 ID 已设置的对象插入到生成的 ID 表中。如果 ID 字段的值为 null 或默认值 (0, ...),则数据库将生成 ID。并非所有数据库类型都支持此功能(例如 Derby)。这是关于这个特定主题的another discussion


我认为正确的做法是在内存中构建您的对象图,将 proper Customer 关联到他们的Order 对象之前其中的磁盘。如果您将客户读入内存,则读入Order 对象并在每个对象上设置真正的Customer 对象。然后,当您在数据库中创建每个Customer 对象时,ORMLite 会将id 字段更改为生成的字段,这也会在每个Order 中保存的customer_id 字段上更改它。

如果您有大量数据并且无法一次将其全部读入内存(或出于其他原因),那么您始终可以构建一个 Map&lt;Integer,Integer&gt; 并保存映射到 XML 的 Customer id在数据库中创建后获得的 ID。然后,当您加载 Order 对象时,您可以在外来对象上设置新的更正 ID。

希望这会有所帮助。让我知道更多关于你如何阅读对象的细节,我可以给出一个更好的例子来说明如何构建对象图。

【讨论】:

  • 嗯,是的,我同意在内存中创建所有内容并在保存任何内容之前设置所有对象关系都可以,但是对于最简单或小型数据集来说,这是一个解决方案。并且它打开了一个完整的“另一罐蠕虫”:如果数据集是另一个桌面或服务器数据库的一部分怎么办 - 重写 ID 肯定会破坏事情。或者,如果 ID 用于其他用途,例如创建账单或交货通知,并且有人需要从备份中恢复,该怎么办?在数据库恢复时更改 ID 是每个自尊的数据库管理员的一大禁忌......
  • 如果您在谈论数据库恢复,我同意更改 id 是不明智的。我以为您在谈论一个“小型”Android 应用程序,该应用程序正在从可能存在重叠 id 的 XML 导入其他记录。如果在其他数据库中引用了重叠的 id,那么您还有其他问题。我的答案的第二部分没有帮助吗?它向您展示了如何使用第二个对象将未生成的 ID 插入到同一个表中。
  • 另外,我在回答中非常明确地指出,在内存中组装对象仅适用于少量数据。你真的阅读了整个答案吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
  • 2019-03-21
相关资源
最近更新 更多