-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: SQLite DATETIME FormatException
PostPosted: Fri Dec 09, 2005 3:29 pm 
Newbie

Joined: Fri Dec 09, 2005 2:38 pm
Posts: 1
Location: Bellevue, Washington
[nhibernate-1.0.1.0; SQLite ADO.NET 0.21_x86; sqlitedll-3_2_7; .NET 1.0.3705.6018]

Not sure if this is a SQLite bug or what. Anyway, when I manually create a db with DATETIME columns then everything is fine. But when I use SchemaExport with the bundled SQLiteDialect then Save works but Load fails, because the logical DATETIME columns have become SQLite NUMERIC columns, containing numbers not parseable by DateTime.

Strangely, SQLiteDialect maps DateTime to TEXT, not DATETIME or NUMERIC. I guess that's actually an attempt to avoid the NUMERIC mapping, since [1] implies that's what DATETIME becomes by default. However, like I said above, if DATETIME is used without trying to second-guess SQLite then I do in fact get a TEXT affinity which results in the correct behavior (values parseable by DateTime). Repro code and output is below.

So the solution seems to be to replace

Code:
RegisterColumnType(DbType.DateTime, "TEXT");


with

Code:
RegisterColumnType(DbType.DateTime, "DATETIME");


in SQLiteDialect.cs. Don't know about DbType.Time.

Ayende's NHibernate Query Analyzer has apparently avoided this problem by using hard-coded ddl, which also specifies DATETIME and VARCHAR types instead of TEXT.

Anyone seen this before? Anyone want to put this into JIRA? Someone might want to make a note in [2], I dunno. I'm fine with using my own SQLiteDialect replacement at the moment.

cmb


[1] http://www.sqlite.org/datatype3.html
[2] http://wiki.nhibernate.org/display/NH/SQLite

BTW, how do I specify a different connection string for use only during SchemaExport? SQLite requires you add "New=True" when executing against a db for the first time. After that New=True will delete your db at every execution. Right now I am dumping the ddl to file and executing it manually with New=True, which is somewhat annoying.

BTW again, that ddl doesn't even work unmodified: I have to cut out the DROP statements, since Finisar throws an exception when you try to drop a nonexistant table. I don't suppose you can tell SchemaExport to exclude the drops or something? Not a big deal I guess.

--
Config:

Code:
<session-factory name="NHibernate.Examples">
  <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
  <property name="connection.driver_class">NHibernate.Driver.SQLiteDriver</property>
  <property name="connection.connection_string">Data Source=nhibernate.db;Version=3</property>
  <property name="show_sql">false</property>
  <property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
  <property name="use_outer_join">true</property>
  <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
  <mapping assembly="NHibernate.Examples" />
</session-factory>


Code:
<class name="NHibernate.Examples.QuickStart.User, NHibernate.Examples" table="users">
  <id name="Id" column="LogonId" type="String" length="20"><generator class="assigned" /></id>
  <property name="UserName" column="Name" type="String" length="40"/>
  <property name="Password" type="String" length="20"/>
  <property name="EmailAddress" type="String" length="40"/>
  <property name="LastLogon" type="DateTime"/>
</class>


--
Code fragments from an entry point class added to NHibernate.Examples:

Code:
private static void CreateDB (string path, string ddl)
{
  using (SQLiteConnection cx = new SQLiteConnection("Data Source="+path+";Version=3;New=True"))
  using (IDbCommand cmd = cx.CreateCommand())
  {
    cx.Open();
    string[] stmts = ddl.Split('\n');
    for (int i = 0; i < stmts.Length; i++)
    {
      if (stmts[i].ToLower().StartsWith("create"))  // skip drops (finisar throws exception)
      {
        cmd.CommandText = stmts[i];
        cmd.ExecuteNonQuery();
      }
    }
  }
}


Code:
if (true)
{
  CreateDB("nhibernate.db", "create table users (LogonId VARCHAR(20) primary key, Name VARCHAR(40) not null, Password VARCHAR(20) not null, EmailAddress VARCHAR(40) not null, LastLogon DATETIME not null)");
}
else  // get ADOException-->FormatException below...
{
  Configuration cfg = new Configuration();
  cfg.AddAssembly("NHibernate.Examples");

  SchemaExport se = new SchemaExport(cfg);
  se.SetOutputFile("setup.sql");
  se.Execute(true, false, false, false);

  using (StreamReader sr = File.OpenText("setup.sql"))
  {
    CreateDB("nhibernate.db", sr.ReadToEnd());
  }
  //executes: "create table users (LogonId TEXT not null, Name TEXT, Password TEXT, EmailAddress TEXT, LastLogon TEXT, primary key (LogonId))"
}

new UserFixture().ValidateQuickStart();

--
Output with manual "LastLogon DATETIME":

Code:
NHibernate :INSERT INTO users (Name, Password, LastLogon, EmailAddress, LogonId) VALUES (@p0, @p1, @p2, @p3, @p4)
NHibernate :SELECT user0_.LogonId as LogonId0_, user0_.Name as Name0_, user0_.Password as Password0_, user0_.LastLogon as LastLogon0_, user0_.EmailAddress as EmailAdd4_0_ FROM users user0_ WHERE user0_.LogonId=@p0
NHibernate :UPDATE users SET Name = @p0, Password = @p1, LastLogon = @p2, EmailAddress = @p3 WHERE LogonId = @p4
NHibernate :SELECT this.LogonId as LogonId0_, this.Name as Name0_, this.Password as Password0_, this.LastLogon as LastLogon0_, this.EmailAddress as EmailAdd4_0_ FROM users this WHERE this.LastLogon > @p0


--
Output with SchemaExport "LastLogon TEXT":

Code:
NHibernate :INSERT INTO users (Name, Password, LastLogon, EmailAddress, LogonId) VALUES (@p0, @p1, @p2, @p3, @p4)
NHibernate :SELECT user0_.LogonId as LogonId0_, user0_.Name as Name0_, user0_.Password as Password0_, user0_.LastLogon as LastLogon0_, user0_.EmailAddress as EmailAdd4_0_ FROM user
s user0_ WHERE user0_.LogonId=@p0

Unhandled Exception: NHibernate.ADOException: could not load: [NHibernate.Examples.QuickStart.User#joe_cool] ---> System.FormatException: String was not recognized as a valid DateTime.
   at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
   at System.DateTime.Parse(String s, IFormatProvider provider, DateTimeStyles styles)
   at System.DateTime.Parse(String s, IFormatProvider provider)
   at System.Convert.ToDateTime(String value, IFormatProvider provider)
   at System.String.System.IConvertible.ToDateTime(IFormatProvider provider)
   at System.Convert.ToDateTime(Object value)
   at NHibernate.Type.DateTimeType.Get(IDataReader rs, Int32 index)
   at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name)
   at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String[] names, ISessionImplementor session, Object owner)
   at NHibernate.Type.AbstractType.Hydrate(IDataReader rs, String[] names, ISessionImplementor session, Object owner)
   at NHibernate.Loader.Loader.Hydrate(IDataReader rs, Object id, Object obj, ILoadable persister, ISessionImplementor session, String[][] suffixedPropertyColumns)
   at NHibernate.Loader.Loader.LoadFromResultSet(IDataReader rs, Int32 i, Object obj, Key key, String suffix, LockMode lockMode, ILoadable rootPersister, ISessionImplementor session)
   at NHibernate.Loader.Loader.InstanceNotYetLoaded(IDataReader dr, Int32 i, ILoadable persister, String suffix, Key key, LockMode lockMode, Key optionalObjectKey, Object optionalObject, IList hydratedObjects, ISessionImplementor session)
   at NHibernate.Loader.Loader.GetRow(IDataReader rs, ILoadable[] persisters, String[] suffixes, Key[] keys, Object optionalObject, Key optionalObjectKey, LockMode[] lockModes, IList hydratedObjects, ISessionImplementor session)
   at NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, IList hydratedObjects, Object optionalObject, Object optionalId, Key[] keys, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Object optionalObject, Object optionalId, Object[] optionalCollectionKeys, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Object optionalObject, Object optionalId, Object[] optionalCollectionKeys, Boolean returnProxies)
   at NHibernate.Loader.EntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId)
   at NHibernate.Loader.EntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject)
   at NHibernate.Persister.EntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session)
   --- End of inner exception stack trace ---
   at NHibernate.Persister.EntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session)
   at NHibernate.Impl.SessionImpl.DoLoad(Type theClass, Object id, Object optionalObject, LockMode lockMode, Boolean checkDeleted)
   at NHibernate.Impl.SessionImpl.DoLoadByClass(Type clazz, Object id, Boolean checkDeleted, Boolean allowProxyCreation)
   at NHibernate.Impl.SessionImpl.Load(Type clazz, Object id)
   at NHibernate.Examples.QuickStart.UserFixture.ValidateQuickStart() in c:\products\thirdparty\nhibernate-1.0.1.0\src\nhibernate.examples\quickstart\userfixture.cs:line 44
   at NHibernate.Examples.Class1.Main(String[] args) in c:\products\thirdparty\nhibernate-1.0.1.0\src\nhibernate.examples\class1.cs:line 90


--
Another fragment:

Code:
DataSet ds = ADOHelper.ExecuteDataSet("Data Source=nhibernate.db;Version=3", "SELECT LastLogon FROM users", null);
Console.WriteLine (ds.Tables[0].Rows[0][0].ToString());

--
Output with manual "LastLogon DATETIME":

Code:
12/9/2005 9:28:14 AM


--
Output with SchemaExport "LastLogon TEXT":

Code:
632697176390000000


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 10, 2005 8:32 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
I guess we can fix that, I think that when the dialect was created there was no DATETIME in SQLite yet, but I might be mistaken.


Top
 Profile  
 
 Post subject: Database indexes from mapping files...
PostPosted: Tue Feb 21, 2006 12:34 am 
Beginner
Beginner

Joined: Thu Dec 08, 2005 6:49 pm
Posts: 49
I'm using SchemaExport to create file based databases when the user wants to start a new database.

Can database indexes be specified in mapping files such that SchemaExport automatically builds them? It looks like it should be possible according to nhibernate-mapping-2.0.xsd, which states that property tags may contain an "index" attribute of type string. However this attribute doesn't seem to be documented so I'm not sure if it refers to database or collection indexing.

What about multi column indexes? Based on this post http://forum.hibernate.org/viewtopic.php?t=944578, it sounds like I probably need to manually create them after SchemaExport.

On a slightly different topic, is it work adding indexes to all my foreign key columns when using SQLite?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 21, 2006 6:50 pm 
Beginner
Beginner

Joined: Thu Dec 08, 2005 6:49 pm
Posts: 49
Oops, I've posted a reply instead of new thread... how embarrasment.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.