예제 #1
0
        public static void CreateOrUpdateTable(SqlServerDatabase database, TableMapping mapping)
        {
            if (!database.TableExists(mapping.TableName))
            {
                // this is the easy case, we need to create the table
                string createTable = MappingEngine.GetCreateTableScript(mapping);
                database.ExecuteNonQuery(createTable);
            }
            else
            {
                StringBuilder log = new StringBuilder();

                // the hard part, figure out if table needs to be altered...
                TableMapping         actual  = LoadTableMetadata(database, mapping);
                List <ColumnMapping> renames = new List <ColumnMapping>();
                StringBuilder        sb      = new StringBuilder();
                // See if any new columns need to be added.
                foreach (ColumnMapping c in mapping.Columns)
                {
                    ColumnMapping ac = actual.FindColumn(c.ColumnName);
                    if (ac == null)
                    {
                        if (!string.IsNullOrEmpty(c.OldColumnName))
                        {
                            ac = actual.FindColumn(c.OldColumnName);
                            if (ac != null)
                            {
                                // this column needs to be renamed, ALTER TABLE doesn't allow renames, so the most efficient way to do it
                                // is add the new column, do an UPDATE to copy all the values over, then DROP the old column.
                                if (c.IsPrimaryKey || ac.IsPrimaryKey)
                                {
                                    throw new NotImplementedException("Cannot rename the primary key automatically, sorry");
                                }
                                // we delimerately do NOT copy the AllowNulls because we can't set that yet.
                                ColumnMapping clone = new ColumnMapping()
                                {
                                    ColumnName    = c.ColumnName,
                                    OldColumnName = c.OldColumnName,
                                    MaxLength     = c.MaxLength,
                                    Precision     = c.Precision,
                                    Scale         = c.Scale,
                                    SqlType       = c.SqlType,
                                    AllowNulls    = true // because we can't set this initially until we populate the column.
                                };
                                renames.Add(clone);
                            }
                        }


                        sb.Append(string.Format("ALTER TABLE [{0}] ADD ", mapping.TableName));
                        c.GetPartialSqlDefinition(sb);

                        string cmd = sb.ToString();
                        log.AppendLine(cmd);
                        database.ExecuteScalar(cmd);
                        sb.Length = 0;
                    }
                }

                if (renames.Count > 0)
                {
                    sb.Length = 0;
                    // now copy the data across to the new column that was added.
                    foreach (ColumnMapping c in renames)
                    {
                        if (sb.Length > 0)
                        {
                            sb.AppendLine(",");
                        }
                        sb.Append(string.Format("[{0}] = [{1}]", c.ColumnName, c.OldColumnName));
                        actual.Columns.Add(c);
                    }

                    string update = string.Format("UPDATE [{0}] SET ", mapping.TableName) + sb.ToString();
                    log.AppendLine(update);
                    database.ExecuteScalar(update);
                    sb.Length = 0;
                }

                // See if any columns need to be dropped.
                foreach (ColumnMapping c in actual.Columns)
                {
                    ColumnMapping ac = mapping.FindColumn(c.ColumnName);
                    if (ac == null)
                    {
                        string drop = string.Format("ALTER TABLE [{0}]  DROP  COLUMN [{1}] ", mapping.TableName, c.ColumnName);
                        log.AppendLine(drop);
                        database.ExecuteScalar(drop);
                    }
                }

                // Lastly see if any types or maxlengths need to be changed.
                foreach (ColumnMapping c in actual.Columns)
                {
                    ColumnMapping ac = mapping.FindColumn(c.ColumnName);
                    if (ac != null)
                    {
                        if (c.MaxLength != ac.MaxLength || c.SqlType != ac.SqlType || c.Precision != ac.Precision || c.Scale != ac.Scale ||
                            c.AllowNulls != ac.AllowNulls)
                        {
                            if (sb.Length > 0)
                            {
                                sb.AppendLine(",");
                            }
                            sb.Append(string.Format("ALTER TABLE [{0}]  ALTER COLUMN ", mapping.TableName));
                            ac.GetSqlDefinition(sb);

                            string alter = sb.ToString();
                            log.AppendLine(alter);
                            database.ExecuteScalar(alter);
                            sb.Length = 0;
                        }
                    }
                }

                if (log.Length > 0)
                {
                    database.AppendLog(log.ToString());
                }
            }
        }