You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework/Connected.Data/Schema/Sql/DataCopy.cs

91 lines
2.6 KiB

2 years ago
using System.Data;
using System.Text;
namespace Connected.Data.Schema.Sql
{
internal class DataCopy : TableTransaction
{
public DataCopy(ExistingSchema existing, string temporaryName)
{
Existing = existing;
TemporaryName = temporaryName;
}
private ExistingSchema Existing { get; }
public string TemporaryName { get; }
protected override async Task OnExecute()
{
await Context.Execute(CommandText);
}
private string CommandText
{
get
{
var text = new StringBuilder();
var columnSet = new StringBuilder();
var sourceSet = new StringBuilder();
var comma = string.Empty;
foreach (var column in Context.Schema.Columns)
{
if (column.IsVersion)
continue;
var existing = Existing.Columns.FirstOrDefault(f => string.Equals(column.Name, f.Name, StringComparison.OrdinalIgnoreCase));
if (existing is null)
continue;
columnSet.Append($"{comma}{Escape(column.Name)}");
if (NeedsConversion(column) && (existing.DataType != column.DataType || existing.Precision != column.Precision || existing.Scale != column.Scale))
sourceSet.Append($"{comma}CONVERT({ConversionString(column)},{Escape(column.Name)})");
else
sourceSet.Append($"{comma}{Escape(column.Name)}");
comma = ",";
}
text.AppendLine($"IF EXISTS (SELECT * FROM {Escape(Existing.SchemaName(), Existing.Name)})");
text.AppendLine($"EXEC ('INSERT INTO {Escape(Context.Schema.SchemaName(), TemporaryName)} ({columnSet.ToString()})");
text.AppendLine($"SELECT {sourceSet.ToString()} FROM {Escape(Existing.SchemaName(), Existing.Name)}')");
return text.ToString();
}
}
private static string ConversionString(ISchemaColumn column)
{
return column.DataType switch
{
DbType.Byte => "tinyint",
DbType.Currency => "money",
DbType.Decimal => $"decimal({column.Precision}, {column.Scale})",
DbType.Double => "real",
DbType.Int16 => "smallint",
DbType.Int32 => "int",
DbType.Int64 => "bigint",
DbType.SByte => "smallint",
DbType.Single => "float",
DbType.UInt16 => "int",
DbType.UInt32 => "bigint",
DbType.UInt64 => "float",
DbType.VarNumeric => $"numeric({column.Precision}, {column.Scale})",
_ => throw new NotSupportedException(),
};
}
private static bool NeedsConversion(ISchemaColumn column)
{
return column.DataType switch
{
DbType.Byte or DbType.Currency or DbType.Decimal or DbType.Double or DbType.Int16 or DbType.Int32 or DbType.Int64 or DbType.SByte
or DbType.Single or DbType.UInt16 or DbType.UInt32 or DbType.UInt64 or DbType.VarNumeric => true,
_ => false,
};
}
}
}