tags:

views:

103

answers:

2

I was psyched about the possibility of using SQLite as a database solution during development so that I could focus on writing the code first and dynamically generating the db at runtime using NHibernate's ShemaExport functionality. However, I'm running into a few issues, not the least of which is that it seems that SQLite requires me to use Int64 for my primary keys (vs, say, Int32 or Guid). Is there any way around this?

Note: I should specify that this is in the context of an app using NHibernate. It is not strictly speaking the case that one can't create a table in SQLite with an INT datatype, but the behavior when you save and retrieve the data seems to indicate that it's being stored and/or retrieved as Int64.

A: 

It does not require you to use Int64, however, it is possible that it only allows that when you specify a numeric primary key. Because sqlite doesn't really have referential integrity checking (though there has been recent discussion of this and perhaps dr hipp has even implemented, i haven't checked lately), all primary key means is "Make this column unique and create an index on it". there isn't much special about it. You can certainly use varchar or text for a primary key. for example, this works:

create table t_test (
       theID varchar(36) primary key,
       nm varchar(50)
       )

in the above you could use theID to store a guid in text form.

More info can be found here: http://www.sqlite.org/lang_createtable.html#rowid

@weenet ... per your comments, the following code works just fine. 

i think you need to post your code if you're still having troubles.

create table t_test2 (
       theID int32 primary key,
       nm varchar(50)
       );
insert into t_test2 (theID, nm) values (1, 'don');
insert into t_test2 (theID, nm) values (2, 'weenet');
select * from t_test2;

additionally, this code works fine (varchar as a primary key):

create table t_test (
       theID varchar(36) primary key,
       nm varchar(50)
       )

insert into t_test (theID, nm) values ('abcdefg', 'don');
insert into t_test (theID, nm) values ('hijklmnop', 'weenet');
select * from t_test
Don Dickinson
oh, i should say that i tried this:create table t_test2 ( theID int32 primary key, nm varchar(50) )and it worked fine, so i guess i'd need a sample of the create statement you're using to explorer further solutions to your issue.
Don Dickinson
Try creating an object with such a key, saving and retrieving it. I believe you'll get an error regarding an attempt to cast Int64 to Int32.
sydneyos
SQLite added support for foreign keys in version 3.6.19 (2009-10-14).
dan04
-1 for use of `varchar(36)` and `varchar(50)` and `int32` which seems to indicate SQLite actually lends a greater amount of significance to these types than it does. SQLite only supports `TEXT`, `INT`, `REAL`, and `NULL` data. Everything else is just translated internally to one of these.
Sam
@Sam ... wow that was cheap ... it was just an example. i didn't say anything about the available data types in sqlite. i am quite aware of how sqlite treats data types. i was trying to demonstrate some things that work so i can get to the heart of the OP's problem. I still don't understand why he's having a problem. have a nice day ...
Don Dickinson
@Don Dickinson, The OP seems to have a misunderstanding of how SQLite works with data types and I think your code sample reinforces this misunderstanding.
Sam
+1  A: 

SQLite will let you use any field in your table as a PRIMARY KEY. Doing so will implicitly create a UNIQUE index on the field. This is then the field that you, as a developer, can consider to be the primary unique identifier for the field. It can be any supported SQLite data type (below).

SQLite will always create an implicit internal numeric identifier for every table. It will have several aliases including RowID, OID, and _ROWID_. If you create your primary key as INTEGER PRIMARY KEY then it will use the same field as your primary key and SQLite's internal numeric identifier.

SQLite doesn't have a concept of Int32 or Int64 or Guid data types. It only has four data types: INT, REAL, TEXT, and BLOB. When you run DDL against SQLite if you use anything other than these four identifiers, SQLite will use a set of rules to determine which type to use. Basically, Int32 and Int64 are treated as aliases of INT and end up doing the exact same thing.

Even once you've created the tables with the data types you mentioned for each field, all you set is the type affinity for that field. SQLite does not enforce data types. Any data can be put into any field regardless of the declared type. SQLite will use the type affinity to convert data if possible, so if you insert '123' as a text string into an INT field, it will store it as the number 123.

The only exception to the type affinity is INTEGER PRIMARY KEY FIELDS. Those must be integers.

Integers in SQLite are always stored with a variable length field. So depending on the size of the integer, you may actually get an Int32 back for some rows an Int64 for others, all within the same field. This depends on the wrapper you're using, in this case NHibernate (I guess with System.Data.SQLite).

Sam
Just to close the loop on this, I've marked this as the accepted answer as it does address the title of the post. Now that I know more, I was asking the wrong question. The issue is that, when you use an INT datatype in SQLite and you retrieve it in code (C#, anyway), it comes back as Int64, so your properties have to be declared as long to avoid an InvalidCast exception (or, I guess, you could do the extra work to intercept the object retrieval if you're using NHIbernate or another ORM and do the cast explicitly).
sydneyos