我可以暂时暂停 ORMLite 中自动生成的 ID 吗?
我在我目前正在编写的一个小应用程序中使用 Android 和 ORMLite。该应用程序的目标是具有有效的导入/导出功能,为此我使用简单的 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),而新生成的客户 id 是 1(在新的空数据库中)。订单也一样。但由于他们引用了 id=2 的客户,因此他们之间的链接被破坏了。
因此,在这个有点冗长的解释之后,我的问题是:有没有办法告诉 ORMLite 获取 generatedId 字段提供的值并使用它运行,而不是覆盖它?如果创建函数在表中找到具有相同 ID 的行时生成任何异常,我会没事的,但会继续保存记录,否则... 我想到了一个解决方法:所有对象都应该可以使用 Comparator 接口按 ID 排序;使用要导入的对象对 ArrayList 进行排序;对于每个对象 - 将假定的 id 读入 int, - 使用 dao.create 保存到数据库, - 如果对象的新 id 与假定的 id 不同,则通过 dao.updateId 更改它, - 移动到列表中的下一个对象。但这似乎太麻烦而且容易出错:如果 create 方法尝试生成一个 id,而您刚刚使用 updateId 将其重新分配给了先前的对象,该怎么办?
我不相信我的情况如此罕见,以至于没有人遇到过这种情况。我希望有一个解决方案!
此致, 托多尔
I am using Android with ORMLite in a small app I am currently writing. The app aims to have a working Import/Export function, for which I use Simple XML framework. And everything works great, up to a point.
The situation is as follows: Object A contains a foreign key referencing Object B, which references Object C through a foreign key itself. Exporting a database is great. Importing works to, with a small caveat, namely that it works as long as the IDs of all object are sequential and start from 1. But if the database is fragmented, i.e. I deleted a record here and there, after I export the database, I have "holes" in the generated XML structure. Example objects could be:
@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
}
Let's say I have a database with 2 customers (id 1 and 2), which hold respectively orders from 1 through 5 and 6 through 8. Exporting this and then re-importing in a clean database works great. If however I delete customer 1 and their orders and export it, the exporter will write their id as they are, i.e.
<customer id="2">...</customer>
and
<order id="6">...</order>
<order id="7">...</order>
<order id="8">...</order>
<order id="9">...</order>
etc. When I import the data into a fresh database, I would first save the customer object via
custDao.create((Customer)x);
and then each of their orders via
orderDao.create((Order)o);
The problem is that the create function disregards the provided id (which is not 0) and the newly generated id for customer is 1 (in a fresh, empty database). Same for the orders. But since they reference customer with id=2, the link between them is broken.
So after this somewhat long-winded explanation, here is my question: Is there a way to tell ORMLite to take the provided value for a generatedId field and run with it, instead of overwriting it? I would be OK, if any Exception is generated in case the create function finds row already in the table with the same ID, but would proceed with saving the record otherwise...
I have thought of a work-around for this: all the objects should be sortable by ID using the Comparator interface; sort the ArrayList with objects to be imported; for each object - read supposed id into an int, - save to database using dao.create, - if the object's new id is different than supposed id, change it via dao.updateId, - move to the next object in the list... But that seems too cumbersome and error-prone: What if the create method tries to generate an id, which you just re-assigned to a previous object with updateId?
I don't believe my situation is so rare, that no one has encountered this before. I would appreciate a solution!
Best regards,
Todor
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
ORMLite 支持
@DatabaseField
注释的allowGenerateIdInsert=true
选项允许将 ID 已设置到生成 ID 表中的对象插入。如果 ID 字段的值为空或默认值(0,...),则数据库将生成 ID。并非所有数据库类型都支持此功能(例如 Derby)。这是关于此特定主题的另一个讨论。我确实认为这里正确的做法是在内存中构建对象图,将正确
Customer
与其Order
对象相关联在将其中一个保存到磁盘之前。如果您将客户读入内存,则读入Order
对象并在每个对象上设置真正的Customer
对象。然后,当您在数据库中创建每个Customer
对象时,ORMLite 会将id
字段更改为生成的字段,这会在customer_id
字段上更改它也保存在每个Order
中。如果您有大量数据并且无法一次将其全部读入内存(或由于某种其他原因),那么您始终可以构建一个
Map
并保存XML 中的 Customer
id 映射到您在数据库中创建后获得的 id。然后,当您加载Order
对象时,您可以在外部对象上设置新的更正 ID。希望这有帮助。让我了解有关如何读取对象的更多详细信息,我可以提供有关如何构建对象图的更好示例。
ORMLite supports a
allowGeneratedIdInsert=true
option to@DatabaseField
annotation that allows inserting of an object with the ID already set into a generated-id table. If the value of the ID field is null or default value (0, ...) then the database will generate the ID. This is not supported by all database types (Derby for example). Here's another discussion about this specific topic.I do think the proper thing to do here is to build your object graph in memory, associating the proper
Customer
on theirOrder
objects before saving an of them to disk. If you read your Customers into memory, then read in theOrder
objects and set the realCustomer
object on each one. When you then create eachCustomer
object in the database, ORMLite will change theid
field to the generated one which would change it on thecustomer_id
field saved in eachOrder
as well.If you have a ton of data and can't read it all into memory at one (or for some other reason) then you could always build a
Map<Integer,Integer>
and save theCustomer
id from the XML mapped to the id you get after you create it in the database. Then when you load in theOrder
objects you can set the new corrected id on the foreign object.Hope this helps. Let me know some more details about how you are reading in the objects and I can give a better example of how to build the object graph.