using System;
using System.Linq;
using System.Linq.Expressions;
using Signum.Engine.Maps;
using Signum.Engine.Properties;
using Signum.Entities;
using Signum.Entities.Reflection;
using Signum.Utilities;
using System.Data;
using System.Collections.Generic;
using Signum.Utilities.DataStructures;
namespace Signum.Engine
{
public static class Administrator
{
public static void NewDatabaseBasic()
{
RemoveAllScript().TryDoC(a=>a.ExecuteLeaves());
CreateTablesScript().TryDoC(a => a.ExecuteLeaves());
InsertEnumValuesScript().TryDoC(a => a.ToSimple().ExecuteNonQuery());
if (Schema.Current.Tables.ContainsKey(typeof(TypeDN)))
{
InsertTypesScript().TryDoC(a => a.ToSimple().ExecuteNonQuery());
Schema.Current.CacheTypeTable();
}
}
#region Create Tables
public static SqlPreCommand CreateTablesScript()
{
Schema schema = Schema.Current;
SqlPreCommand createTables = schema.Tables.Select(t => SqlBuilder.CreateTableSql(t.Value)).Combine(Spacing.Double);
SqlPreCommand foreignKeys = schema.Tables.Select(t => SqlBuilder.AlterTableForeignKeys(t.Value)).Combine(Spacing.Double);
SqlPreCommand indices = schema.Tables.Select(t => SqlBuilder.CreateIndicesSql(t.Value)).NotNull().Combine(Spacing.Double);
SqlPreCommand collectionTables = schema.Tables.Select(t => t.Value.CreateCollectionTables()).Combine(Spacing.Triple);
return SqlPreCommand.Combine(Spacing.Triple, createTables, foreignKeys, indices, collectionTables);
}
#endregion
public static SqlPreCommand InsertEnumValuesScript()
{
return (from t in Schema.Current.Tables.Values
let enumType = Reflector.ExtractEnumProxy(t.Type)
where enumType != null
select (from item in Enum.GetValues(enumType).Cast<object>()
let ei = EnumProxy.FromEnum((Enum)item).Do(e => e.PreSaving())
select t.InsertSql(ei, Forbidden.None, false)).Combine(Spacing.Simple)).Combine(Spacing.Double);
}
public static SqlPreCommand InsertTypesScript()
{
Table table = Schema.Current.Table<TypeDN>();
return (from ei in SchemaTypes()
select table.InsertSql(ei, Forbidden.None, true)).Combine(Spacing.Simple);
}
#region Eliminar Todo
public static readonly SqlPreCommandSimple RemoveAllConstraintsScript = new SqlPreCommandSimple(
@"declare @schema nvarchar(128), @tbl nvarchar(128), @constraint nvarchar(128)
DECLARE @sql nvarchar(255)
declare cur cursor fast_forward for
select distinct cu.constraint_schema, cu.table_name, cu.constraint_name
from information_schema.table_constraints tc
join information_schema.referential_constraints rc on rc.unique_constraint_name = tc.constraint_name
join information_schema.constraint_column_usage cu on cu.constraint_name = rc.constraint_name
open cur
fetch next from cur into @schema, @tbl, @constraint
while @@fetch_status <> -1
begin
select @sql = 'ALTER TABLE ' + @schema + '.' + @tbl + ' DROP CONSTRAINT ' + @constraint
exec sp_executesql @sql
fetch next from cur into @schema, @tbl, @constraint
end
close cur
deallocate cur");
public static readonly SqlPreCommandSimple RemoveAllTablesScript = new SqlPreCommandSimple(
@"declare @schema nvarchar(128), @tbl nvarchar(128)
DECLARE @sql nvarchar(255)
declare cur cursor fast_forward for
select distinct table_schema, table_name
from information_schema.tables where table_type = 'BASE TABLE'
open cur
fetch next from cur into @schema, @tbl
while @@fetch_status <> -1
begin
select @sql = 'DROP TABLE ' + @schema + '.' + @tbl + ';'
exec sp_executesql @sql
fetch next from cur into @schema, @tbl
end
close cur
deallocate cur");
public static readonly SqlPreCommandSimple RemoveAllViewsScript = new SqlPreCommandSimple(
@"declare @schema nvarchar(128), @tbl nvarchar(128)
DECLARE @sql nvarchar(255)
declare cur cursor fast_forward for
select distinct table_schema, table_name
from information_schema.tables where table_type = 'VIEW'
open cur
fetch next from cur into @schema, @tbl
while @@fetch_status <> -1
begin
select @sql = 'DROP VIEW ' + @schema + '.' + @tbl + ';'
exec sp_executesql @sql
fetch next from cur into @schema, @tbl
end
close cur
deallocate cur");
public static SqlPreCommand RemoveAllScript()
{
return SqlPreCommand.Combine(Spacing.Double, RemoveAllViewsScript, RemoveAllConstraintsScript, RemoveAllTablesScript);
}
#endregion
static List<TypeDN> SchemaTypes()
{
var lista = (from tab in Schema.Current.Tables.Values
let type = Reflector.ExtractEnumProxy(tab.Type) ?? tab.Type
select new TypeDN
{
ClassName = type.Name,
TableName = tab.Name,
Name = type.FriendlyName()
}).ToList();
return lista;
}
#region MultiColumnIndex
public static void AddMultiColumnIndex<T>(bool unique, params Expression<Func<T, object>>[] columns) where T : IdentifiableEntity
{
AddMultiColumnIndexScript<T>(unique, columns).ToSimple().ExecuteNonQuery();
}
public static SqlPreCommand AddMultiColumnIndexScript<T>(bool unique, params Expression<Func<T, object>>[] columns) where T : IdentifiableEntity
{
Schema schema = ConnectionScope.Current.Schema;
return AddMultiColumnIndexScript(schema.Table<T>(), unique, columns.Select(fun => schema.Field<IColumn, T>(fun)).ToArray());
}
public static void AddMultiColumnIndex(ITable table, bool unique, params IColumn[] columns)
{
AddMultiColumnIndexScript(table, unique, columns).ToSimple().ExecuteNonQuery();
}
public static SqlPreCommand AddMultiColumnIndexScript(ITable table, bool unique, params IColumn[] columns)
{
return SqlBuilder.CreateIndex(unique ? Index.Unique : Index.Multiple, table.Name, columns.Select(c => c.Name).ToArray());
}
#endregion
public static SqlPreCommand SynchronizeAllScript()
{
return SqlPreCommand.Combine(Spacing.Triple,
SynchronizeSchemaScript(),
SynchronizeTypesScript(),
SynchronizeEnumsScript());
}
public static SqlPreCommand SynchronizeSchemaScript()
{
return Synchronizer.SynchronizeSchema();
}
public static SqlPreCommand SynchronizeTypesScript()
{
if(!Schema.Current.Tables.ContainsKey(typeof(TypeDN)))
return null;
Table table = Schema.Current.Table<TypeDN>();
var should = SchemaTypes().ToDictionary(a=>a.ClassName);
Dictionary<string, TypeDN> current;
if (Database.View<SchemaTables>().Any(a=>a.TABLE_NAME == table.Name))
current = Database.RetrieveAll<TypeDN>().ToDictionary(a => a.ClassName);
else
current = new Dictionary<string, TypeDN>();
var result = should.OuterJoinDictionaryCC(current, (str, s, c) => new { s, c }).Select(p =>
{
var s = p.Value.s;
var c = p.Value.c;
if (s != null && c != null)
{
c.TableName = s.TableName;
c.Name = s.Name;
if (c.SelfModified)
return table.UpdateSql(c, Forbidden.None);
}
else if (s != null)
{
return table.InsertSql(s, Forbidden.None, true);
}
else if (c != null)
{
return table.Delete(c.id);
}
return null;
}).ToArray();
return SqlPreCommand.Combine(Spacing.Double, result);
}
public static SqlPreCommand SynchronizeEnumsScript()
{
string[] currentTables = Database.View<SchemaTables>().Select(a => a.TABLE_NAME).ToArray();
Schema schema = Schema.Current;
List<SqlPreCommand> commands = new List<SqlPreCommand>();
foreach (var table in schema.Tables.Values)
{
Type enumType = Reflector.ExtractEnumProxy(table.Type);
if (enumType != null)
{
var should = Enum.GetValues(enumType).Cast<Enum>().Select(e=> EnumProxy.FromEnum(e)).ToDictionary(a=>a.Id);
Dictionary<int,IdentifiableEntity> current;
if (currentTables.Contains(table.Name))
current = Database.RetrieveAll(table.Type).ToDictionary(a => a.Id);
else
current = new Dictionary<int, IdentifiableEntity>();
var com = should.OuterJoinDictionaryCC(current, (str, s, c) => new { s, c }).Select(p =>
{
var s = p.Value.s;
var c = p.Value.c;
if (s != null && c != null)
{
c.PreSaving();
if (c.SelfModified)
return table.UpdateSql(c, Forbidden.None);
}
else if (s != null)
{
return table.InsertSql(s, Forbidden.None, false);
}
else if (c != null)
{
return table.Delete(c.id);
}
return null;
}).Combine(Spacing.Simple);
commands.Add(com);
}
}
return SqlPreCommand.Combine(Spacing.Double, commands.ToArray());
}
}
}