using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace Eucalypto.SchemaGenerator
{
//Note about SQL Server 2005 varbinary(max) and nvarchar(max):
//
// SQL Server 2005 dialect defines these properties:
// RegisterColumnType( DbType.String, 1073741823, "NVARCHAR(MAX)" );
// RegisterColumnType( DbType.AnsiString, 2147483647, "VARCHAR(MAX)" );
// RegisterColumnType( DbType.Binary, 2147483647, "VARBINARY(MAX)" );
// so to use the new NVARCHAR(MAX) and VARBINARY(MAX) you must simply use as length 1073741823 and 2147483647 respectively
//
/// <summary>
/// Class used to automatically generate the schema of the database.
/// </summary>
public class GenericGenerator
{
private Configuration mConfiguration;
public GenericGenerator(Configuration config)
{
mConfiguration = config;
}
/// <summary>
/// Create the specified database feature
/// </summary>
/// <param name="section"></param>
public void CreateSchemaTable(SchemaSection section)
{
NHibernate.Cfg.Configuration hibConfig = mConfiguration.CreateConfiguration();
Type[] entities = GetEntities(section);
foreach (Type ent in entities)
hibConfig.AddClass(ent);
NHibernate.Tool.hbm2ddl.SchemaExport ddlExport = new NHibernate.Tool.hbm2ddl.SchemaExport(hibConfig);
ddlExport.Create(false, true);
}
/// <summary>
/// Get the status of the schema.
/// </summary>
/// <param name="section"></param>
/// <returns></returns>
public SchemaStatus GetStatus(SchemaSection section)
{
try
{
Type[] entities = GetEntities(section);
//TODO Check if there is a way to see if a table exist without catching exception
using (TransactionScope transaction = new TransactionScope(mConfiguration))
{
foreach (Type ent in entities)
{
try
{
NHibernate.ICriteria criteria = transaction.NHibernateSession.CreateCriteria(ent);
criteria.SetMaxResults(1);
//If the query works is because the table exist
criteria.List();
}
catch (Exception)
{
//If the query fails is because the table don't exist
return SchemaStatus.NotExist;
}
}
return SchemaStatus.AlreadyExist;
}
}
catch (Exception)
{
return SchemaStatus.ConnectionError;
}
}
//public SchemaStatus GetStatus(SchemaSection section)
//{
// try
// {
// string query;
// if (string.Equals(mConfiguration.Connection_DriverClass, Configuration.DRIVER_SQLITE, StringComparison.InvariantCultureIgnoreCase))
// query = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='{0}'";
// else if (string.Equals(mConfiguration.Connection_DriverClass, Configuration.DRIVER_SQLSERVER, StringComparison.InvariantCultureIgnoreCase))
// query = "SELECT COUNT(*) FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{0}]') AND type in (N'U')";
// else
// return SchemaStatus.UnknownDriver;
// Type[] entities = GetEntities(section);
// int founded = 0;
// foreach (Type ent in entities)
// {
// using (TransactionScope transaction = new TransactionScope(mConfiguration))
// {
// IDbCommand command = transaction.CreateDbCommand();
// command.CommandText = string.Format(query, ent.Name);
// //Note: I don't use command parameters for a better support for special database (where the parameters are not identified by @)
// //IDbDataParameter param = transaction.CreateDbCommandParameter(command, "@tableName", DbType.String, ent.Name);
// //command.Parameters.Add(param);
// int count = Convert.ToInt32( command.ExecuteScalar() );
// if (count == 1)
// founded++;
// }
// }
// if (entities.Length == founded)
// return SchemaStatus.AlreadyExist;
// else if (founded == 0)
// return SchemaStatus.NotExist;
// else if (entities.Length > founded)
// return SchemaStatus.PartialExist;
// else
// throw new EucalyptoException("Returned value not valid");
// }
// catch (Exception)
// {
// return SchemaStatus.ConnectionError;
// }
//}
public static Type[] GetEntities(SchemaSection section)
{
switch (section)
{
case SchemaSection.Forum:
return new Type[] { typeof(Forum.Category), typeof(Forum.Topic), typeof(Forum.Message) };
case SchemaSection.Role:
return new Type[] { typeof(Roles.Role), typeof(Roles.UserInRole) };
case SchemaSection.User:
return new Type[] { typeof(Membership.User) };
case SchemaSection.Profile:
return new Type[] { typeof(Profile.ProfileUser), typeof(Profile.ProfileProperty) };
case SchemaSection.Wiki:
return new Type[] { typeof(Wiki.Category), typeof(Wiki.Article), typeof(Wiki.VersionedArticle), typeof(Wiki.FileAttachment) };
case SchemaSection.News:
return new Type[] { typeof(News.Category), typeof(News.Item) };
default:
throw new ArgumentException("SchemaSection value not supported", "section");
}
}
public static SchemaSection[] GetSections()
{
return (SchemaSection[])Enum.GetValues(typeof(SchemaSection));
}
}
public enum SchemaStatus
{
AlreadyExist,
PartialExist,
NotExist,
ConnectionError,
UnknownDriver
}
public enum SchemaSection
{
User,
Role,
Forum,
Profile,
Wiki,
News
}
}