Wrong autoincrement value in sqlite using JPA - sqlite

I'm working on a simple project using sqlite, JPA and eclipseLink.
First I create my Person table in my database with this:
CREATE TABLE Person (
idPerson INTEGER PRIMARY KEY AUTOINCREMENT,
firstname TEXT DEFAULT 'NULL',
birthdate DATETIME DEFAULT 'NULL'
)
and then add a new test entry (in order to generate the sqlite_sequence table)
INSERT INTO [Person] ([firstname], [birthdate]) VALUES ('Foo', '1145-11-12 00:00:00')
All the successive insertion are done using JPA, where in the Person class I use this notation for the person id:
#GeneratedValue(generator="sqlite_person")
#TableGenerator(name="sqlite_person", table="sqlite_sequence",
pkColumnName="name", valueColumnName="seq",
pkColumnValue="Person")
#Column(name="idPerson")
private int id;
The first JPA insertion is ok (that is, new new inserted person has id = 2) but then I get an increment of 50 instead of only 1 (so the third inserted person has id = 52, the fourth 102 and so on).
I read that "making modifications to this table will likely perturb the AUTOINCREMENT key generation algorithm" [ref]
Is my problem related to this, even if in theory I'm not modifying that table?
Any kind of suggestion in order to resolve the problem?

You are using Autoincrement in the database, which means the database will assign a value to the id when it is inserted, but then you tell the JPA provider to use Table generation. Table generation requires that the JPA provider use a special table to keep track of sequence values, looking it up and assigning it before inserting the entity row in the database. This conflicts with what you set up in the database.
http://wiki.eclipse.org/EclipseLink/Examples/JPA/PrimaryKey explains sequencing fairly well. You will need to try using #GeneratedValue(strategy=GenerationType.IDENTITY) instead of table generation so that inserts by JPA use the same sequence allocation as inserts outside of JPA.

At the end, in order to solve the problem, I just added two optional elements for the TableGenerator annotation (i.e. initialValue, allocationSize).
So the new annotation for the ID is like this:
#GeneratedValue(generator="sqlite_person")
#TableGenerator(name="sqlite_person", table="sqlite_sequence",
pkColumnName="name", valueColumnName="seq",
pkColumnValue="Person",
initialValue=1, allocationSize=1)
#Column(name="idPerson")
private int id;
I think it works also without the initial value, but like this I also avoid to insert random entries (because it seems that the sqlite_sequence table is automatically generated already when I create the Person table)

Related

How to future proof these possible requirement changes (swaping primary key columns) with a dynamodb table design?

I have the following data structure
item_id String
version String
_id String
data String
_id is simply a UUID to identify the item. There is no need to search for a row by this field yet.
As of now, item_id, an id generated by an external system, is the a primary key. i.e. Given the item_id, I want to be able retrieve version, _id and data from the dynamodb table.
item_id -> (version, _id, data)
Therefore I am setting item_id as the partition key.
I have two questions for future-proofing (evolution of) the above "schema":
In the future, if I want to incorporate version (version number of the item) into the primary key, can I just modify the table and add it to be the partition key?
If I also want to make the data searchable by _id, is it feasible modify the table to assign _id to be the partition key (It is a unique value because it is a UUID) and reassign item_id to be a search key?
I want to avoid creation of new dynamodb table and data migration to create new key structures, because it may lead to down time.
You cannot update primary keys in DynamoDB. From the docs:
You cannot use UpdateItem to update any primary key attributes. Instead, you will need to delete the item, and then use PutItem to create a new item with new attributes.
If you wanted to make data searchable by _id, you could introduce a secondary index with the _id field as the partition key of the index.
For example, let's say your data looked like this:
If you defined a secondary index on _id, the index would look like this (same data as the previous example, just a different logical view):
DynamoDB doesn't currently have any native versioning functionality, so you'll have to incorporate that into your data model. Fortunately, there's lots of discussion about this use case on the web. AWS has a document of DynamoDB "Best Practices", including an example of versioning.

Create table with auto increment

I have to create a table with autoincrement column. I am creating an web app with sqlite as a background and sql alchemy is the orm layer.Python and Flask as front end. I am creating some department list and department id should be auto incremented.When I try to add department through UI I dont provide department id.Because department id is the primary key and should be auto incremented.I have added the department name and department jobs through UI without any error.But when I try to list the departments list I am getting error.
AttributeError: 'NoneType' object has no attribute 'department_id'
What I tried is,My sqlite
create table Departments(department_id primarykey integer autoincrement,department_name char,department_jobs char);
When I try creating this schema I am getting an error called 'syntax error near autoincrement'
I tried by using capital letter,auto_increment,auto increment.
Nothing is working
My sql alchemy looks like this
class Departments(db.Model):
"Adding the department"
department_id = db.Column(db.Integer,primary_key=True)
department_name = db.Column(db.String(50),nullable=False)
department_jobs = db.Column(db.String(40),nullable=False)
What I am expecting here is how do I do the auto incrementin sqllite and sqlalchemy so that I can use it in both frontend and backend.
You have coded PRIMARYKEY instead of PRIMARY KEY and you should also code INTEGER PRIMARY KEY as the column type should appear first.
There is no need, from your explanation, to code AUTOINCREMENT.
Not using AUTOINCREMENT will be more efficient and will as far as you are concerned do the same thing. i.e. if the value for the department_id is not supplied, then SQLite will automatically generate a value which will be 1 for the first row that is inserted and then typically 1 greater for the next row and so on (SQLite does not guarantee montonically increasing numbers).
SQLite Autoincrement which includes
The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.
I'd sugggest just using :-
create table Departments(department_id INTEGER PRIMARY KEY,department_name char,department_jobs char);

Unable to determine primary key field on custom table

I have a custom table that I'm basically modeling after the CustGroup table.
The table has two fields, one extends the SysGroup and the other is a Name type. I added an index with AllowDuplicates = No and the one SysGroup field.
And on the table, I set the PrimaryIndex equal to my SysGroup field.
I delete the axapd.aoi file and restarted the AOS. I also ran the cross reference update and SysFlushAOD::main(null);.
When I run the following code, the first line returns 0 and the second 1, meaning it was able to find a primary key.
info(strfmt("MyCustGroup: %1", new SysDictTable(40390).primaryKeyField())); // Returns 0
info(strfmt("CustGroup: %1", new SysDictTable(57).primaryKeyField())); // Returns 1
Any idea what I'm doing wrong?
Your primary key should extend you own extended data type (EDT) extending SysGroup.
In the relations node of the EDT have a normal relation to your table and key field. Then change your key field to extend from your EDT.
Set the TableGroup property of your table to Group.
Then make sure the table succeeds completely the Best Practice check.
If that does not solve your problem, export, delete and import your table.

How to update a aprimary key field with linq to SQL?

I have tbl_names with following fields:
Id int
Name nvarchar(10)
family nvarchar(20)
Id Name Family
1 John Smith
and suppose Id and name are primary key together(compound primary key).
and I want to update name field according to the value of Id field.
DataclassesContext dac=new DataClassesContext();
var query=from record in Dac.tbl_name where record.id=1 select record;
query.name="Raymond";
Dac.Submitchanges();
but I encounter following error:
Value of member 'co_Workshop' of an object of type 'Tbl_Workshop' changed.
A member defining the identity of the object cannot be changed.
Consider adding a new object with new identity and deleting the existing one instead.
Is it because of name field is primary key? why can't I update a primary key field using linq?
I am not sure that you should find a way around this. I cannot imagine why it would be a good idea to change a value in a PK. The entire nature of a PK is that it is a stable identifier of the row.
In your case, you should drop and recreate the PK to be just the "Id" field and then if you need to improve performance on queries filtering on "name" then just add an Index on the "name" field. The fact that you only use the "Id" field to find the record supports this idea.
EDIT:
I answered before there were comments to the Question. Now that I see the comment from the OP about "it is an old database and can't change it's structure", I would say that if there are no FKs pointing to this PK then this should be a fairly straight-forward change (to drop and recreate the PK with just the "Id" field as I mentioned above). If there are FKs pointing to it then an option (though not a great option and it might not work on all RDBMS's) is to:
Drop the FKs
Drop the PK
Create the new PK on just the "Id" field
Create a UNIQUE INDEX on "Id" and "Name"
Recreate the FK's to point to the UNIQUE INDEX
This will work on Microsoft SQL Server and as much as I dislike the idea of a FK pointing to a UNIQUE INDEX, it should allow for the same structure that you have now plus LINQ will just see the single field PK on "Id" and allow for the update.
Where possible, a workaround is to delete the record whose primary key value needs updating and create a new record in its place.
It looks like there are ways around it, like I mentioned above. Linq won't let you change the primary key.
http://social.msdn.microsoft.com/Forums/en/linqprojectgeneral/thread/64064c2d-1484-4a00-a2c4-764bcb6b774a
Had the same problem. For legacy reasons, I couldn't remove the column I needed to update from being part of the primary key.
A simple solution was to not use Linq in this case, but use T_SQL and do a simple update.
update tbl_name set name = 'Raymond' where id = 1

SQLITE: Unable to remove an unnamed primary key

I have a sqlite table that was originally created with:
PRIMARY KEY (`column`);
I now need to remove that primary key and create a new one. Creating a new one is easy, but removing the original seems to be the hard part. If I do
.indices tablename
I don't get the primary key. Some programs show the primary key as
Indexes: 1
[] PRIMARY
The index name is typically in the [].
Any ideas?
You can't.
PRAGMA INDEX_LIST('MyTable');
will give you a list of indices. This will include the automatically generated index for the primary key which will be called something like 'sqlite_autoindex_MyTable_1'.
But unfortunately you cannot drop this index...
sqlite> drop index sqlite_autoindex_MyTable_1;
SQL error: index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped
All you can do is re-create the table without the primary key.
I the database glossary; a primary-key is a type of index where the index order is typically results in the physical ordering of the raw database records. That said any database engine that allows the primary key to be changed is likely reordering the database... so most do not and the operation is up to the programmer to create a script to rename the table and create a new one. So if you want to change the PK there is no magic SQL.
select * from sqlite_master;
table|x|x|2|CREATE TABLE x (a text, b text, primary key (`a`))
index|sqlite_autoindex_x_1|x|3|
You'll see that the second row returned from my quick hack has the index name in the second column, and the table name in the third. Try seeing if that name is anything useful.

Resources