Click here to Skip to main content
15,896,201 members
Articles / Web Development / ASP.NET

Signum Framework Principles

Rate me:
Please Sign up or sign in to vote.
4.74/5 (27 votes)
25 Jul 2011CPOL18 min read 99.5K   1.1K   86  
Explains the philosophy behind Signum Framework, an ORM with a full LINQ Provider that encourages an entities-first approach.
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()); 
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Signum Software
Spain Spain
I'm Computer Scientist, one of the founders of Signum Software, and the lead developer behind Signum Framework.

www.signumframework.com

I love programming in C#, Linq, Compilers, Algorithms, Functional Programming, Computer Graphics, Maths...

Comments and Discussions