/// <summary>
        /// Creates a list of new DataTypes, creating as well a list of new Tables with all members of type as columns
        /// </summary>
        public static IEnumerable <DataType> DefaultMap(IEnumerable <Type> types)
        {
            //we will store here all types that are actually persistent
            List <DataType> persistentTypes = new List <DataType>();
            Random          random          = new Random();

            //map primary keys first, so we allow to foreign keys and inheritance to be correctly mapped
            foreach (Type type in types)
            {
                //skip enums and interfaces
                if (type.GetTypeInfo().IsEnum || type.GetTypeInfo().IsInterface)
                {
                    continue;
                }

                //ignore types with no primary key
                var pk = GetMappableMembers(type).Where(m => DataMember.IsPrimaryKey(m));

                if (pk.Count() == 0)
                {
                    continue;
                }

                DataType dtype = new DataType(type);
                AllDataTypes.Add(dtype);

                foreach (var memberInfo in pk)
                {
                    //create datamember
                    dtype.AddMember(memberInfo.Name);
                }

                persistentTypes.Add(dtype);
            }

            foreach (DataType dtype in persistentTypes)
            {
                //create inheritance foreign keys
                if (dtype.BaseDataType != null)
                {
                    ForeignKey foreignKey = new ForeignKey();
                    foreignKey.Table       = dtype.Table;
                    foreignKey.RemoteTable = dtype.BaseDataType.Table;
                    foreignKey.Name        = "FK_" + dtype.Name + "_" + dtype.BaseDataType.Name + "_" + random.Next();

                    //we asume that primary keys on parent and child tables have the same number and order of related columns
                    for (int i = 0; i < dtype.PrimaryKey.Count(); i++)
                    {
                        DataMember pk     = dtype.PrimaryKey.ToArray()[i];
                        DataMember basePk = dtype.BaseDataType.PrimaryKey.ToArray()[i];

                        foreignKey.Columns.Add(new Tuple <Column, Column>(pk.Column, basePk.Column));
                    }

                    dtype.Table.ForeignKeys.Add(foreignKey);
                }

                //map non primary key members now
                foreach (var memberInfo in GetMappableMembers(dtype.InnerType).Where(m => !DataMember.IsPrimaryKey(m)))
                {
                    Type returnType = MemberExpression.GetReturnType(memberInfo);

                    //is this a collection of a mapped type? if so, ignore since this must be a 1-1, 1-many or many-many relationship and must be mapped somewhere else
                    if (DataType.IsCollection(returnType) && IsMapped(returnType.GetCollectionItemType()))
                    {
                        continue;
                    }

                    //its a persistent type, with it's own table, map as a foreign key with one or more columns for the primary key
                    if (IsMapped(returnType))
                    {
                        //we asume this datatype is already mapped along with it's primery key
                        DataType returnDataType = returnType;

                        ForeignKey foreignKey = new ForeignKey();
                        foreignKey.Table       = dtype.Table;
                        foreignKey.RemoteTable = returnDataType.Table;
                        foreignKey.Name        = "FK_" + dtype.Name + "_" + memberInfo.Name + "_" + random.Next();

                        foreach (DataMember pk in returnDataType.PrimaryKey.ToList())
                        {
                            Column column = new Column();
                            column.Name         = memberInfo.Name + "_" + pk.Member.Expression.Replace('.', '_');
                            column.Table        = dtype.Table;
                            column.IsPrimaryKey = false;
                            column.IsNullable   = !RequiredValidator.IsRequired(memberInfo);
                            column.DbType       = DbTypeMapper.Parse(pk.Member.ReturnType);

                            if (column.IsString)
                            {
                                column.Length = StringLengthValidator.GetMaxLength(pk.Member.FinalMemberInfo);
                            }

                            dtype.Table.Columns.Add(column);
                            foreignKey.Columns.Add(new Tuple <Column, Column>(column, pk.Column));

                            //create datamember
                            dtype.AddMember(memberInfo.Name + "." + pk.Member, column);
                        }

                        dtype.Table.ForeignKeys.Add(foreignKey);
                    }
                    //just map as a atomic value
                    else
                    {
                        Column column = new Column();
                        column.Name         = memberInfo.Name;
                        column.Table        = dtype.Table;
                        column.IsNullable   = !RequiredValidator.IsRequired(memberInfo);
                        column.IsPrimaryKey = false;

                        //create datamember
                        DataMember dmember = dtype.AddMember(memberInfo.Name, column);

                        //is this a regular atomic value?
                        if (DbTypeMapper.DbTypeMap.ContainsValue(returnType) && returnType != typeof(object))
                        {
                            column.DbType = DbTypeMapper.Parse(returnType);
                        }
                        else if (returnType.GetTypeInfo().IsEnum)
                        {
                            column.DbType = DbType.Int32;
                        }
                        //this is an non-atomic object, but its not mapped as a DataType, so we serialize it as json
                        else
                        {
                            column.DbType     = DbType.String;
                            dmember.Converter = new Conversions.Json <object>();
                        }

                        if (column.IsString)
                        {
                            column.Length = Data.Validation.StringLengthValidator.GetMaxLength(memberInfo);
                        }

                        dtype.Table.Columns.Add(column);
                    }
                }

                yield return(dtype);
            }
        }
        public Type GetType(int ordinal)
        {
            DbType dbType = OKHOSTING.Sql.SQLite.DataBase.Parse(CurrentResult[ordinal].SQLiteType);

            return(DbTypeMapper.Parse(dbType));
        }
Beispiel #3
0
        /// <summary>
        /// Returns the full schema of the database including tables, indexes, foreign keys, etc.
        /// </summary>
        /// <remarks>
        /// It's very slow for large databases
        /// </remarks>
        public static DataBaseSchema Load(DataBase database, string schemaProvider)
        {
            DataBaseSchema schema = new DataBaseSchema();
            DatabaseSchema schemaReader;

            using (var dbReader = new DatabaseSchemaReader.DatabaseReader(database.ConnectionString, schemaProvider))
            {
                dbReader.AllTables();
                dbReader.AllViews();

                try
                {
                    dbReader.AllStoredProcedures();
                }
                catch { }

                try
                {
                    dbReader.AllUsers();
                }
                catch { }

                schemaReader = dbReader.DatabaseSchema;
            }

            foreach (DatabaseTable dbt in schemaReader.Tables)
            {
                if (dbt.PrimaryKeyColumn == null)
                {
                    continue;
                }

                dbt.PrimaryKeyColumn.AddIdentity();

                var table = new Table()
                {
                    Name              = dbt.Name,
                    DataBase          = schema,
                    IdentityIncrement = dbt.PrimaryKeyColumn.IdentityDefinition.IdentityIncrement,
                    IdentitySeed      = dbt.PrimaryKeyColumn.IdentityDefinition.IdentitySeed,
                };

                schema.Tables.Add(table);
            }

            foreach (DatabaseTable dbt in schemaReader.Tables)
            {
                if (dbt.PrimaryKeyColumn == null)
                {
                    continue;
                }

                var table = schema[dbt.Name];

                foreach (DatabaseColumn dbc in dbt.Columns)
                {
                    Column column = new Column()
                    {
                        Name               = dbc.Name,
                        Table              = table,
                        Description        = dbc.Description,
                        IsNullable         = dbc.Nullable,
                        IsAutoNumber       = dbc.IsAutoNumber,
                        ComputedDefinition = dbc.ComputedDefinition,
                        DefaultValue       = dbc.DefaultValue,
                        IsPrimaryKey       = dbc.IsPrimaryKey,
                        Length             = (uint?)dbc.Length,
                        Ordinal            = dbc.Ordinal,
                        Precision          = dbc.Precision,
                        Scale              = dbc.Scale,
                    };


                    if (dbc.DataType != null)
                    {
                        column.DbType = DbTypeMapper.Parse(dbc.DataType.GetNetType());
                    }
                    else
                    {
                        if (dbc.DbDataType.StartsWith("varchar"))
                        {
                            column.DbType = DbType.AnsiString;
                        }
                        else if (dbc.DbDataType.StartsWith("int"))
                        {
                            column.DbType = DbType.Int32;
                        }
                        else if (dbc.DbDataType.StartsWith("decimal"))
                        {
                            column.DbType = DbType.Decimal;
                        }
                        else if (dbc.DbDataType.StartsWith("datetime"))
                        {
                            column.DbType = DbType.DateTime;
                        }
                        else if (dbc.DbDataType.StartsWith("money"))
                        {
                            column.DbType = DbType.Currency;
                        }
                        else if (dbc.DbDataType.StartsWith("char"))
                        {
                            column.DbType = DbType.AnsiStringFixedLength;
                        }
                        else if (dbc.DbDataType.StartsWith("text"))
                        {
                            column.DbType = DbType.AnsiString;
                        }
                    }

                    table.Columns.Add(column);
                }

                foreach (DatabaseIndex dbi in dbt.Indexes)
                {
                    Index index = new Index()
                    {
                        Name      = dbi.Name,
                        Table     = table,
                        Direction = SortDirection.Ascending,
                        Unique    = dbi.IsUnique,
                    };

                    foreach (DatabaseColumn dbc in dbi.Columns)
                    {
                        index.Columns.Add(table[dbc.Name]);
                    }

                    table.Indexes.Add(index);
                }

                foreach (DatabaseTrigger dbtr in dbt.Triggers)
                {
                    DataBaseOperation operation = DataBaseOperation.Insert;
                    Enum.TryParse <DataBaseOperation>(dbtr.TriggerEvent, true, out operation);

                    Trigger trigger = new Trigger()
                    {
                        TriggerBody  = dbtr.TriggerBody,
                        TriggerEvent = operation,
                        Table        = table,
                    };

                    table.Triggers.Add(trigger);
                }

                foreach (DatabaseConstraint dbcons in dbt.CheckConstraints)
                {
                    if (dbcons.ConstraintType == ConstraintType.Check)
                    {
                        CheckConstraint constraint = new CheckConstraint()
                        {
                            Expression = dbcons.Expression,
                            Table      = table,
                        };

                        table.CheckConstraints.Add(constraint);
                    }
                    else if (dbcons.ConstraintType == ConstraintType.ForeignKey)
                    {
                        ForeignKey foreignKey = new ForeignKey()
                        {
                            Name         = dbcons.Name,
                            DeleteAction = schema.ParseConstraintAction(dbcons.DeleteRule),
                            UpdateAction = schema.ParseConstraintAction(dbcons.UpdateRule),
                            RemoteTable  = schema[dbcons.RefersToTable],
                            Table        = table,
                        };

                        var referencedColumns = dbcons.ReferencedColumns(schemaReader).ToArray();
                        for (int i = 0; i < dbcons.Columns.Count; i++)
                        {
                            foreignKey.Columns.Add(new Tuple <Column, Column>(table[dbcons.Columns[i]], foreignKey.RemoteTable[referencedColumns[i]]));
                        }

                        table.ForeignKeys.Add(foreignKey);
                    }
                }
            }

            foreach (DatabaseView dbv in schemaReader.Views)
            {
                View view = new View()
                {
                    Name        = dbv.Name,
                    Command     = dbv.Sql,
                    Description = dbv.Description,
                    DataBase    = schema,
                };

                schema.Views.Add(view);
            }

            foreach (DatabaseUser dbu in schemaReader.Users)
            {
                User user = new User()
                {
                    Name     = dbu.Name,
                    DataBase = schema,
                };

                schema.Users.Add(user);
            }

            return(schema);
        }