diff --git a/Library/Library.csproj b/Library/Library.csproj index d8edfaa..160d651 100644 --- a/Library/Library.csproj +++ b/Library/Library.csproj @@ -1,4 +1,4 @@ - + 10.0 net5.0;net6.0;net48 @@ -22,7 +22,8 @@ + - \ No newline at end of file + diff --git a/Library/Models/Column.cs b/Library/Models/Column.cs index 851fcf4..5a5e1f5 100644 --- a/Library/Models/Column.cs +++ b/Library/Models/Column.cs @@ -107,6 +107,7 @@ private string ScriptBase() { case "geography": case "xml": case "sysname": + case "geometry": val.Append($" {IsNullableText}"); if (IncludeDefaultConstraint) val.Append(DefaultText); if (Identity != null) val.Append(IdentityText); @@ -161,6 +162,7 @@ internal static Type SqlTypeToNativeType(string sqlType) { case "binary": case "varbinary": case "image": + case "geometry": return typeof(byte[]); default: return typeof(string); diff --git a/Library/Models/Table.cs b/Library/Models/Table.cs index 54f140b..51c3d79 100644 --- a/Library/Models/Table.cs +++ b/Library/Models/Table.cs @@ -162,8 +162,12 @@ public void ExportData(string conn, TextWriter data, string tableHint = null) { using (var dr = cm.ExecuteReader()) { while (dr.Read()) { foreach (var c in cols) { - if (dr[c.Name] is DBNull) + var ordinal = dr.GetOrdinal(c.Name); + if (dr.IsDBNull(ordinal)) data.Write(_nullValue); + else if (dr.GetDataTypeName(ordinal).EndsWith(".sys.geometry")) + // https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2012/ms143179(v=sql.110)?redirectedfrom=MSDN#sql-clr-data-types-geometry-geography-and-hierarchyid + data.Write(StringUtil.ToHexString(dr.GetSqlBytes(ordinal).Value)); else if (dr[c.Name] is byte[]) data.Write(StringUtil.ToHexString((byte[])dr[c.Name])); else if (dr[c.Name] is DateTime) @@ -311,6 +315,7 @@ public static object ConvertType(string sqlType, string val) { case "binary": case "varbinary": case "image": + case "geometry": return StringUtil.FromHexString(val); default: return val; diff --git a/Test/Integration/TableTest.cs b/Test/Integration/TableTest.cs index 18de5e4..f65dc67 100644 --- a/Test/Integration/TableTest.cs +++ b/Test/Integration/TableTest.cs @@ -246,8 +246,41 @@ public async Task TestScript() { t.Columns.Add(new Column("bb", "varchar", -1, true, null)); t.Columns.Add(new Column("cc", "xml", true, null)); t.Columns.Add(new Column("dd", "hierarchyid", false, null)); + t.Columns.Add(new Column("ee", "geometry", false, null)); await using var testDb = await _dbHelper.CreateTestDbAsync(); await testDb.ExecSqlAsync(t.ScriptCreate()); } + + [Fact] + public async Task TestImportExportGeometryData() { + var t = new Table("dbo", "Shape"); + t.Columns.Add(new Column("id", "int", false, null)); + t.Columns.Add(new Column("shape", "geometry", false, null)); + t.Columns.Find("id").Identity = new Identity(1, 1); + t.AddConstraint(new Constraint("PK_Shape", "PRIMARY KEY", "id")); + + await using var testDb = await _dbHelper.CreateTestDbAsync(); + await testDb.ExecSqlAsync(t.ScriptCreate()); + + var dataIn = + @"1 0000000001040300000000000000000059400000000000005940000000000000344000000000008066400000000000806640000000000080664001000000010000000001000000FFFFFFFF0000000002" + Environment.NewLine + + @"2 00000000010405000000000000000000000000000000000000000000000000C0624000000000000000000000000000C062400000000000C0624000000000000000000000000000C062400000000000000000000000000000000001000000020000000001000000FFFFFFFF0000000003" + Environment.NewLine; + + var filename = Path.GetTempFileName(); + + var writer = File.AppendText(filename); + writer.Write(dataIn); + writer.Flush(); + writer.Close(); + + try { + t.ImportData(testDb.GetConnString(), filename); + var sw = new StringWriter(); + t.ExportData(testDb.GetConnString(), sw); + Assert.Equal(dataIn, sw.ToString()); + } finally { + File.Delete(filename); + } + } }