From: <pa...@us...> - 2011-03-26 18:27:37
|
Revision: 5543 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5543&view=rev Author: patearl Date: 2011-03-26 18:27:30 +0000 (Sat, 26 Mar 2011) Log Message: ----------- Support foreign keys on SQLite. Breaking change for databases that don't support alter table and have DDL-time foreign key correctness checks. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs trunk/nhibernate/src/NHibernate/Dialect/Schema/SQLiteMetaData.cs trunk/nhibernate/src/NHibernate/Driver/SQLite20Driver.cs trunk/nhibernate/src/NHibernate/Mapping/Table.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2011-03-26 16:35:24 UTC (rev 5542) +++ trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2011-03-26 18:27:30 UTC (rev 5543) @@ -813,7 +813,10 @@ var script = new List<string>(); - // drop them in reverse order in case db needs it done that way... + if (!string.IsNullOrEmpty(dialect.BeforeDropSchemaCommand)) + script.Add(dialect.BeforeDropSchemaCommand); + + // drop them in reverse order in case db needs it done that way...);); for (int i = auxiliaryDatabaseObjects.Count - 1; i >= 0; i--) { IAuxiliaryDatabaseObject auxDbObj = auxiliaryDatabaseObjects[i]; @@ -861,6 +864,9 @@ } } + if (!string.IsNullOrEmpty(dialect.AfterDropSchemaCommand)) + script.Add(dialect.AfterDropSchemaCommand); + return script.ToArray(); } Modified: trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2011-03-26 16:35:24 UTC (rev 5542) +++ trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2011-03-26 18:27:30 UTC (rev 5543) @@ -645,7 +645,10 @@ { var res = new StringBuilder(200); - res.Append(" add constraint ") + if (SupportsForeignKeyConstraintInAlterTable) + res.Append(" add"); + + res.Append(" constraint ") .Append(constraintName) .Append(" foreign key (") .Append(StringHelper.Join(StringHelper.CommaSpace, foreignKey)) @@ -2413,5 +2416,15 @@ { return false; } - } + + public virtual string BeforeDropSchemaCommand + { + get { return null; } + } + + public virtual string AfterDropSchemaCommand + { + get { return null; } + } + } } Modified: trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs 2011-03-26 16:35:24 UTC (rev 5542) +++ trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs 2011-03-26 18:27:30 UTC (rev 5543) @@ -261,6 +261,23 @@ get { return "select randomblob(16)"; } } + /// <summary> + /// SQLite does not currently support dropping foreign key constraints by alter statements. + /// This means that tables cannot be dropped if there are any rows that depend on those. + /// If there are cycles between tables, it would even be excessively difficult to delete + /// the data in the right order first. Because of this, we just turn off the foreign + /// constraints before we drop the schema and hope that we're not going to break anything. :( + /// </summary> + public override string BeforeDropSchemaCommand + { + get { return "PRAGMA foreign_keys = OFF"; } + } + + public override string AfterDropSchemaCommand + { + get { return "PRAGMA foreign_keys = ON"; } + } + [Serializable] protected class SQLiteCastFunction : CastFunction { Modified: trunk/nhibernate/src/NHibernate/Dialect/Schema/SQLiteMetaData.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Schema/SQLiteMetaData.cs 2011-03-26 16:35:24 UTC (rev 5542) +++ trunk/nhibernate/src/NHibernate/Dialect/Schema/SQLiteMetaData.cs 2011-03-26 18:27:30 UTC (rev 5543) @@ -30,8 +30,8 @@ protected override string GetConstraintName(DataRow rs) { - throw new NotImplementedException(); - } + return Convert.ToString(rs["CONSTRAINT_NAME"]); + } protected override IForeignKeyMetadata GetForeignKeyMetadata(DataRow rs) { Modified: trunk/nhibernate/src/NHibernate/Driver/SQLite20Driver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/SQLite20Driver.cs 2011-03-26 16:35:24 UTC (rev 5542) +++ trunk/nhibernate/src/NHibernate/Driver/SQLite20Driver.cs 2011-03-26 18:27:30 UTC (rev 5543) @@ -1,4 +1,6 @@ using System; +using System.Data; +using System.Data.Common; namespace NHibernate.Driver { @@ -33,6 +35,28 @@ { } + public override IDbConnection CreateConnection() + { + DbConnection connection = (DbConnection)base.CreateConnection(); + connection.StateChange += Connection_StateChange; + return connection; + } + + private static void Connection_StateChange(object sender, StateChangeEventArgs e) + { + if ((e.OriginalState == ConnectionState.Broken || e.OriginalState == ConnectionState.Closed || e.OriginalState == ConnectionState.Connecting) && + e.CurrentState == ConnectionState.Open) + { + DbConnection connection = (DbConnection)sender; + using (DbCommand command = connection.CreateCommand()) + { + // Activated foreign keys if supported by SQLite. Unknown pragmas are ignored. + command.CommandText = "PRAGMA foreign_keys = ON"; + command.ExecuteNonQuery(); + } + } + } + public override bool UseNamedPrefixInSql { get { return true; } Modified: trunk/nhibernate/src/NHibernate/Mapping/Table.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2011-03-26 16:35:24 UTC (rev 5542) +++ trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2011-03-26 18:27:30 UTC (rev 5543) @@ -427,6 +427,17 @@ } } + if (!dialect.SupportsForeignKeyConstraintInAlterTable) + { + foreach (ForeignKey foreignKey in ForeignKeyIterator) + { + if (foreignKey.HasPhysicalConstraint) + { + buf.Append(",").Append(foreignKey.SqlConstraintString(dialect, foreignKey.Name, defaultCatalog, defaultSchema)); + } + } + } + buf.Append(StringHelper.ClosedParen); if (string.IsNullOrEmpty(comment) == false) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |