⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 schemaexport.cs

📁 NHibernate NET开发者所需的
💻 CS
字号:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using log4net;
using NHibernate.Cfg;
using NHibernate.Connection;
using NHibernate.Util;

namespace NHibernate.Tool.hbm2ddl
{
	/// <summary>
	/// Generates ddl to export table schema for a configured <c>Configuration</c> to the database
	/// </summary>
	/// <remarks>
	/// This Class can be used directly or the command line wrapper NHibernate.Tool.hbm2ddl.exe can be
	/// used when a dll can not be directly used.
	/// </remarks>
	public class SchemaExport
	{
		private readonly string[] dropSQL;
		private readonly string[] createSQL;
		private readonly IDictionary<string, string> connectionProperties;
		private string outputFile = null;
		private readonly Dialect.Dialect dialect;
		private string delimiter = null;

		private static readonly ILog log = LogManager.GetLogger(typeof(SchemaExport));

		/// <summary>
		/// Create a schema exported for a given Configuration
		/// </summary>
		/// <param name="cfg">The NHibernate Configuration to generate the schema from.</param>
		public SchemaExport(Configuration cfg)
			: this(cfg, cfg.Properties)
		{
		}

		/// <summary>
		/// Create a schema exporter for the given Configuration, with the given
		/// database connection properties
		/// </summary>
		/// <param name="cfg">The NHibernate Configuration to generate the schema from.</param>
		/// <param name="connectionProperties">The Properties to use when connecting to the Database.</param>
		public SchemaExport(Configuration cfg, IDictionary<string,string> connectionProperties)
		{
			this.connectionProperties = connectionProperties;
			dialect = Dialect.Dialect.GetDialect(connectionProperties);
			dropSQL = cfg.GenerateDropSchemaScript(dialect);
			createSQL = cfg.GenerateSchemaCreationScript(dialect);
		}

		/// <summary>
		/// Set the output filename. The generated script will be written to this file
		/// </summary>
		/// <param name="filename">The name of the file to output the ddl to.</param>
		/// <returns>The SchemaExport object.</returns>
		public SchemaExport SetOutputFile(string filename)
		{
			outputFile = filename;
			return this;
		}

		/// <summary>
		/// Set the end of statement delimiter 
		/// </summary>
		/// <param name="delimiter">The end of statement delimiter.</param>
		/// <returns>The SchemaExport object.</returns>
		public SchemaExport SetDelimiter(string delimiter)
		{
			this.delimiter = delimiter;
			return this;
		}

		/// <summary>
		/// Run the schema creation script
		/// </summary>
		/// <param name="script"><see langword="true" /> if the ddl should be outputted in the Console.</param>
		/// <param name="export"><see langword="true" /> if the ddl should be executed against the Database.</param>
		/// <remarks>
		/// This is a convenience method that calls <see cref="Execute(bool, bool, bool, bool)"/> and sets
		/// the justDrop parameter to false and the format parameter to true.
		/// </remarks>
		public void Create(bool script, bool export)
		{
			Execute(script, export, false, true);
		}

		/// <summary>
		/// Run the drop schema script
		/// </summary>
		/// <param name="script"><see langword="true" /> if the ddl should be outputted in the Console.</param>
		/// <param name="export"><see langword="true" /> if the ddl should be executed against the Database.</param>
		/// <remarks>
		/// This is a convenience method that calls <see cref="Execute(bool, bool, bool, bool)"/> and sets
		/// the justDrop and format parameter to true.
		/// </remarks>
		public void Drop(bool script, bool export)
		{
			Execute(script, export, true, true);
		}

		private void Execute(bool script, bool export, bool format, bool throwOnError, TextWriter exportOutput,
		                     IDbCommand statement, string sql)
		{
			try
			{
				string formatted;
				if (format)
				{
					formatted = Format(sql);
				}
				else
				{
					formatted = sql;
				}

				if (delimiter != null)
				{
					formatted += delimiter;
				}
				if (script)
				{
					Console.WriteLine(formatted);
				}
				log.Debug(formatted);
				if (exportOutput != null)
				{
					exportOutput.WriteLine(formatted);
				}
				if (export)
				{
					statement.CommandText = sql;
					statement.CommandType = CommandType.Text;
					statement.ExecuteNonQuery();
				}
			}
			catch (Exception e)
			{
				log.Warn("Unsuccessful: " + sql);
				log.Warn(e.Message);
				if (throwOnError)
				{
					throw;
				}
			}
		}

		/// <summary>
		/// Executes the Export of the Schema in the given connection
		/// </summary>
		/// <param name="script"><see langword="true" /> if the ddl should be outputted in the Console.</param>
		/// <param name="export"><see langword="true" /> if the ddl should be executed against the Database.</param>
		/// <param name="justDrop"><see langword="true" /> if only the ddl to drop the Database objects should be executed.</param>
		/// <param name="format"><see langword="true" /> if the ddl should be nicely formatted instead of one statement per line.</param>
		/// <param name="connection">
		/// The connection to use when executing the commands when export is <see langword="true" />.
		/// Must be an opened connection. The method doesn't close the connection.
		/// </param>
		/// <param name="exportOutput">The writer used to output the generated schema</param>
		/// <remarks>
		/// This method allows for both the drop and create ddl script to be executed.
		/// This overload is provided mainly to enable use of in memory databases. 
		/// It does NOT close the given connection!
		/// </remarks>
		public void Execute(bool script, bool export, bool justDrop, bool format,
		                    IDbConnection connection, TextWriter exportOutput)
		{
			IDbCommand statement = null;

			if (export && connection == null)
			{
				throw new ArgumentNullException("connection", "When export is set to true, you need to pass a non null connection");
			}
			if (export)
			{
				statement = connection.CreateCommand();
			}

			try
			{
				for (int i = 0; i < dropSQL.Length; i++)
				{
					Execute(script, export, format, false, exportOutput, statement, dropSQL[i]);
				}

				if (!justDrop)
				{
					for (int j = 0; j < createSQL.Length; j++)
					{
						Execute(script, export, format, true, exportOutput, statement, createSQL[j]);
					}
				}
			}
			finally
			{
				try
				{
					if (statement != null)
					{
						statement.Dispose();
					}
				}
				catch (Exception e)
				{
					log.Error("Could not close connection: " + e.Message, e);
				}
				if (exportOutput != null)
				{
					try
					{
						exportOutput.Close();
					}
					catch (Exception ioe)
					{
						log.Error("Error closing output file " + outputFile + ": " + ioe.Message, ioe);
					}
				}
			}
		}

		/// <summary>
		/// Executes the Export of the Schema.
		/// </summary>
		/// <param name="script"><see langword="true" /> if the ddl should be outputted in the Console.</param>
		/// <param name="export"><see langword="true" /> if the ddl should be executed against the Database.</param>
		/// <param name="justDrop"><see langword="true" /> if only the ddl to drop the Database objects should be executed.</param>
		/// <param name="format"><see langword="true" /> if the ddl should be nicely formatted instead of one statement per line.</param>
		/// <remarks>
		/// This method allows for both the drop and create ddl script to be executed.
		/// </remarks>
		public void Execute(bool script, bool export, bool justDrop, bool format)
		{
			IDbConnection connection = null;
			StreamWriter fileOutput = null;
			IConnectionProvider connectionProvider = null;

			Dictionary<string, string> props = new Dictionary<string, string>();
			foreach (KeyValuePair<string, string> de in dialect.DefaultProperties)
			{
				props[de.Key] = de.Value;
			}

			if (connectionProperties != null)
			{
				foreach (KeyValuePair<string, string> de in connectionProperties)
				{
					props[de.Key] = de.Value;
				}
			}

			try
			{
				if (outputFile != null)
				{
					fileOutput = new StreamWriter(outputFile);
				}

				if (export)
				{
					connectionProvider = ConnectionProviderFactory.NewConnectionProvider(props);
					connection = connectionProvider.GetConnection();
				}

				Execute(script, export, justDrop, format, connection, fileOutput);
			}
			catch (HibernateException)
			{
				// So that we don't wrap HibernateExceptions in HibernateExceptions
				throw;
			}
			catch (Exception e)
			{
				log.Error(e.Message, e);
				throw new HibernateException(e.Message, e);
			}
			finally
			{
				if (connection != null)
				{
					connectionProvider.CloseConnection(connection);
					connectionProvider.Dispose();
				}
			}
		}

		/// <summary>
		/// Format an SQL statement using simple rules
		/// </summary>
		/// <param name="sql">The string containing the sql to format.</param>
		/// <returns>A string that contains formatted sql.</returns>
		/// <remarks>
		/// The simple rules to used when formatting are:
		/// <list type="number">
		///		<item>
		///			<description>Insert a newline after each comma</description>
		///		</item>
		///		<item>
		///			<description>Indent three spaces after each inserted newline</description>
		///		</item>
		///		<item>
		///			<description>
		///			If the statement contains single/double quotes return unchanged because
		///			it is too complex and could be broken by simple formatting.
		///			</description>
		///		</item>
		/// </list>
		/// </remarks>
		private static string Format(string sql)
		{
			if (sql.IndexOf("\"") > 0 || sql.IndexOf("'") > 0)
			{
				return sql;
			}

			string formatted;

			if (StringHelper.StartsWithCaseInsensitive(sql, "create table"))
			{
				StringBuilder result = new StringBuilder(60);
				StringTokenizer tokens = new StringTokenizer(sql, "(,)", true);

				int depth = 0;

				foreach (string tok in tokens)
				{
					if (StringHelper.ClosedParen.Equals(tok))
					{
						depth--;
						if (depth == 0)
						{
							result.Append("\n");
						}
					}
					result.Append(tok);
					if (StringHelper.Comma.Equals(tok) && depth == 1)
					{
						result.Append("\n  ");
					}
					if (StringHelper.OpenParen.Equals(tok))
					{
						depth++;
						if (depth == 1)
						{
							result.Append("\n  ");
						}
					}
				}

				formatted = result.ToString();
			}
			else
			{
				formatted = sql;
			}

			return formatted;
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -