Skip to content

Commit e91d3c5

Browse files
committed
Vector and Json bug fixes and unit tests
1 parent ee6a9f9 commit e91d3c5

File tree

14 files changed

+284
-66
lines changed

14 files changed

+284
-66
lines changed

EF.Reverse.POCO.GeneratorV3.sln

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 18
4-
VisualStudioVersion = 18.3.11206.111 d18.3
4+
VisualStudioVersion = 18.3.11206.111
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFramework.Reverse.POCO.Generator", "EntityFramework.Reverse.POCO.Generator\EntityFramework.Reverse.POCO.Generator.csproj", "{FA93A0BD-8B45-43BA-9C57-1D8FD63CAEAE}"
77
EndProject
@@ -46,6 +46,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLServer", "SQLServer", "{
4646
TestDatabases\SQLServer\EfrpgTest_Settings.sql = TestDatabases\SQLServer\EfrpgTest_Settings.sql
4747
TestDatabases\SQLServer\EfrpgTest_Synonyms.sql = TestDatabases\SQLServer\EfrpgTest_Synonyms.sql
4848
TestDatabases\SQLServer\Northwind.sql = TestDatabases\SQLServer\Northwind.sql
49+
ReversePoco.sql = ReversePoco.sql
4950
EndProjectSection
5051
EndProject
5152
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator.Tests.Integration", "Generator.Tests.Integration\Generator.Tests.Integration.csproj", "{BD6836BD-6C08-41EA-A0E3-93EB5AA1D375}"

EntityFramework.Reverse.POCO.Generator/EF.Reverse.POCO.v3.ttinclude

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@
105105
public static List<string> AdditionalFileHeaderText = new List<string>(); // This will put additional lines verbatim at the top of each file under the comments, 1 line per entry
106106
public static List<string> AdditionalFileFooterText = new List<string>(); // This will put additional lines verbatim at the end of each file above the // </auto-generated>, 1 line per entry
107107
public static OrderProperties OrderProperties = OrderProperties.Ordinal; // Order the properties in the generated POCO classes. Ordinal, Alphabetical
108-
public static bool AutoMapSqlServer2025Types = true; // If true, allows custom mapping of SQL Server 2025/Azure SQL vector and json types via UpdateColumn delegate (EFCore 10+ only)
109108

110109
// Language choices
111110
public static GenerationLanguage GenerationLanguage = GenerationLanguage.CSharp;
@@ -3991,7 +3990,7 @@
39913990
BaseClasses = table.BaseClasses,
39923991
InsideClassBody = Settings.WriteInsideClassBody(table),
39933992
HasHierarchyId = table.Columns.Any(x => x.PropertyType.EndsWith("hierarchyid", StringComparison.InvariantCultureIgnoreCase)),
3994-
HasSqlVector = table.Columns.Any(x => x.PropertyType.StartsWith("SqlVector", StringComparison.InvariantCultureIgnoreCase)),
3993+
HasSqlVector = table.Columns.Any(x => x.PropertyType.StartsWith("SqlVector", StringComparison.InvariantCultureIgnoreCase)) && Settings.IsEfCore10Plus(),
39953994
Columns = columnsQuery
39963995
.Where(x => !x.Hidden && !x.ExistsInBaseClass)
39973996
.Select((col, index) => new PocoColumnModel
@@ -7556,6 +7555,11 @@
75567555
var geographyType = isEf6 ? "DbGeography" : "NetTopologySuite.Geometries.Point";
75577556
var geometryType = isEf6 ? "DbGeometry" : "NetTopologySuite.Geometries.Geometry";
75587557

7558+
// SQL Server 2025 / Azure SQL vector type:
7559+
// - EF Core 10+: SqlVector<float> (native support, requires Microsoft.Data.SqlTypes namespace)
7560+
// - EF6/EFCore8/EFCore9: byte[] (fallback - no native support, stored as varbinary internally)
7561+
var vectorType = Settings.IsEfCore10Plus() ? "SqlVector<float>" : "byte[]";
7562+
75597563
return new Dictionary<string, string>
75607564
{
75617565
{ string.Empty, "string" }, // default
@@ -7573,7 +7577,7 @@
75737577
{ "hierarchyid", "Hierarchy.HierarchyId" },
75747578
{ "image", "byte[]" },
75757579
{ "int", "int" },
7576-
{ "json", "string" }, // SQL Server 2025 / Azure SQL native json type
7580+
{ "json", "string" }, // SQL Server 2025 / Azure SQL native json type (string works for all EF versions)
75777581
{ "money", "decimal" },
75787582
{ "numeric", "decimal" },
75797583
{ "real", "float" },
@@ -7585,7 +7589,7 @@
75857589
{ "timestamp", "byte[]" },
75867590
{ "tinyint", "byte" },
75877591
{ "uniqueidentifier", "Guid" },
7588-
{ "vector", "SqlVector<float>" }, // SQL Server 2025 / Azure SQL vector type for AI/ML (requires Microsoft.Data.SqlClient.Types namespace)
7592+
{ "vector", vectorType },
75897593
{ "varbinary", "byte[]" },
75907594
{ "varbinary(max)", "byte[]" }
75917595
};
@@ -13705,9 +13709,12 @@ and limitations under the License.
1370513709
}
1370613710

1370713711
// SQL Server 2025 vector type - include dimension in SqlPropertyType for [Column(TypeName = "vector(n)")]
13712+
// CHARACTER_MAXIMUM_LENGTH returns byte size, not dimension. Each float = 4 bytes, plus 8 bytes overhead.
13713+
// Formula: dimension = (byte_size - 8) / 4
1370813714
if (col.SqlPropertyType.Equals("vector", StringComparison.InvariantCultureIgnoreCase) && col.MaxLength > 0)
1370913715
{
13710-
col.SqlPropertyType = $"vector({col.MaxLength})";
13716+
var vectorDimension = (col.MaxLength - 8) / 4;
13717+
col.SqlPropertyType = $"vector({vectorDimension})";
1371113718
}
1371213719

1371313720
if (col.IsPrimaryKey && !col.IsIdentity && col.IsStoreGenerated && rt.TypeName == "uniqueidentifier")
@@ -20578,7 +20585,7 @@ public class FakeDbContextTransaction : IDbContextTransaction{{#newline}}
2057820585
usings.Add("Microsoft.EntityFrameworkCore");
2057920586

2058020587
if (data.HasSqlVector)
20581-
usings.Add("Microsoft.Data.SqlClient.Types");
20588+
usings.Add("Microsoft.Data.SqlTypes");
2058220589

2058320590
return usings;
2058420591
}
@@ -20944,8 +20951,8 @@ public enum {{EnumName}}{{#newline}}
2094420951
if (data.HasHierarchyId && !usings.Contains("Microsoft.EntityFrameworkCore"))
2094520952
usings.Add("Microsoft.EntityFrameworkCore");
2094620953

20947-
if (data.HasSqlVector && !usings.Contains("Microsoft.Data.SqlClient.Types"))
20948-
usings.Add("Microsoft.Data.SqlClient.Types");
20954+
if (data.HasSqlVector && !usings.Contains("Microsoft.Data.SqlTypes"))
20955+
usings.Add("Microsoft.Data.SqlTypes");
2094920956

2095020957
return usings;
2095120958
}

Generator/Generators/CodeGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ public CodeOutput GeneratePoco(Table table)
493493
BaseClasses = table.BaseClasses,
494494
InsideClassBody = Settings.WriteInsideClassBody(table),
495495
HasHierarchyId = table.Columns.Any(x => x.PropertyType.EndsWith("hierarchyid", StringComparison.InvariantCultureIgnoreCase)),
496-
HasSqlVector = table.Columns.Any(x => x.PropertyType.StartsWith("SqlVector", StringComparison.InvariantCultureIgnoreCase)),
496+
HasSqlVector = table.Columns.Any(x => x.PropertyType.StartsWith("SqlVector", StringComparison.InvariantCultureIgnoreCase)) && Settings.IsEfCore10Plus(),
497497
Columns = columnsQuery
498498
.Where(x => !x.Hidden && !x.ExistsInBaseClass)
499499
.Select((col, index) => new PocoColumnModel

Generator/LanguageMapping/SqlServerToCSharp.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ public Dictionary<string, string> GetMapping()
1212
var geographyType = isEf6 ? "DbGeography" : "NetTopologySuite.Geometries.Point";
1313
var geometryType = isEf6 ? "DbGeometry" : "NetTopologySuite.Geometries.Geometry";
1414

15+
// SQL Server 2025 / Azure SQL vector type:
16+
// - EF Core 10+: SqlVector<float> (native support, requires Microsoft.Data.SqlTypes namespace)
17+
// - EF6/EFCore8/EFCore9: byte[] (fallback - no native support, stored as varbinary internally)
18+
var vectorType = Settings.IsEfCore10Plus() ? "SqlVector<float>" : "byte[]";
19+
1520
return new Dictionary<string, string>
1621
{
1722
{ string.Empty, "string" }, // default
@@ -29,7 +34,7 @@ public Dictionary<string, string> GetMapping()
2934
{ "hierarchyid", "Hierarchy.HierarchyId" },
3035
{ "image", "byte[]" },
3136
{ "int", "int" },
32-
{ "json", "string" }, // SQL Server 2025 / Azure SQL native json type
37+
{ "json", "string" }, // SQL Server 2025 / Azure SQL native json type (string works for all EF versions)
3338
{ "money", "decimal" },
3439
{ "numeric", "decimal" },
3540
{ "real", "float" },
@@ -41,7 +46,7 @@ public Dictionary<string, string> GetMapping()
4146
{ "timestamp", "byte[]" },
4247
{ "tinyint", "byte" },
4348
{ "uniqueidentifier", "Guid" },
44-
{ "vector", "SqlVector<float>" }, // SQL Server 2025 / Azure SQL vector type for AI/ML (requires Microsoft.Data.SqlClient.Types namespace)
49+
{ "vector", vectorType },
4550
{ "varbinary", "byte[]" },
4651
{ "varbinary(max)", "byte[]" }
4752
};

Generator/Readers/DatabaseReader.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,9 +1125,12 @@ public Column CreateColumn(RawTable rt, Table table, IDbContextFilter filter)
11251125
}
11261126

11271127
// SQL Server 2025 vector type - include dimension in SqlPropertyType for [Column(TypeName = "vector(n)")]
1128+
// CHARACTER_MAXIMUM_LENGTH returns byte size, not dimension. Each float = 4 bytes, plus 8 bytes overhead.
1129+
// Formula: dimension = (byte_size - 8) / 4
11281130
if (col.SqlPropertyType.Equals("vector", StringComparison.InvariantCultureIgnoreCase) && col.MaxLength > 0)
11291131
{
1130-
col.SqlPropertyType = $"vector({col.MaxLength})";
1132+
var vectorDimension = (col.MaxLength - 8) / 4;
1133+
col.SqlPropertyType = $"vector({vectorDimension})";
11311134
}
11321135

11331136
if (col.IsPrimaryKey && !col.IsIdentity && col.IsStoreGenerated && rt.TypeName == "uniqueidentifier")

Generator/Settings.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ public static class Settings
7979
public static List<string> AdditionalFileHeaderText = new List<string>(); // This will put additional lines verbatim at the top of each file under the comments, 1 line per entry
8080
public static List<string> AdditionalFileFooterText = new List<string>(); // This will put additional lines verbatim at the end of each file above the // </auto-generated>, 1 line per entry
8181
public static OrderProperties OrderProperties = OrderProperties.Ordinal; // Order the properties in the generated POCO classes. Ordinal, Alphabetical
82-
public static bool AutoMapSqlServer2025Types = true; // If true, allows custom mapping of SQL Server 2025/Azure SQL vector and json types via UpdateColumn delegate (EFCore 10+ only)
8382

8483
// Language choices
8584
public static GenerationLanguage GenerationLanguage = GenerationLanguage.CSharp;

Generator/Templates/TemplateEfCore8.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1425,7 +1425,7 @@ public override List<string> PocoUsings(PocoModel data)
14251425
usings.Add("Microsoft.EntityFrameworkCore");
14261426

14271427
if (data.HasSqlVector)
1428-
usings.Add("Microsoft.Data.SqlClient.Types");
1428+
usings.Add("Microsoft.Data.SqlTypes");
14291429

14301430
return usings;
14311431
}

Generator/Templates/TemplateFileBased.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ public override List<string> PocoUsings(PocoModel data)
8383
if (data.HasHierarchyId && !usings.Contains("Microsoft.EntityFrameworkCore"))
8484
usings.Add("Microsoft.EntityFrameworkCore");
8585

86-
if (data.HasSqlVector && !usings.Contains("Microsoft.Data.SqlClient.Types"))
87-
usings.Add("Microsoft.Data.SqlClient.Types");
86+
if (data.HasSqlVector && !usings.Contains("Microsoft.Data.SqlTypes"))
87+
usings.Add("Microsoft.Data.SqlTypes");
8888

8989
return usings;
9090
}

Tester.Integration.EFCore10/Azure.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// ReSharper disable All
33

44
using Microsoft.Data.SqlClient;
5+
using Microsoft.Data.SqlTypes;
56
using Microsoft.EntityFrameworkCore;
67
using Microsoft.EntityFrameworkCore.ChangeTracking;
78
using Microsoft.EntityFrameworkCore.Design;
@@ -40,6 +41,7 @@ public interface IAzureContext : IDisposable
4041
DbSet<SalesByWeek> SalesByWeeks { get; set; } // SalesByWeek
4142
DbSet<SignatureUsed> SignatureUseds { get; set; } // SignatureUsed
4243
DbSet<sys_DatabaseFirewallRule> sys_DatabaseFirewallRules { get; set; } // database_firewall_rules
44+
DbSet<TestingEfCore10> TestingEfCore10 { get; set; } // Testing_EfCore10
4345
DbSet<VolumeDiscount> VolumeDiscounts { get; set; } // VolumeDiscount
4446

4547
int SaveChanges();
@@ -120,6 +122,7 @@ public AzureContext(DbContextOptions<AzureContext> options)
120122
public DbSet<SalesByWeek> SalesByWeeks { get; set; } // SalesByWeek
121123
public DbSet<SignatureUsed> SignatureUseds { get; set; } // SignatureUsed
122124
public DbSet<sys_DatabaseFirewallRule> sys_DatabaseFirewallRules { get; set; } // database_firewall_rules
125+
public DbSet<TestingEfCore10> TestingEfCore10 { get; set; } // Testing_EfCore10
123126
public DbSet<VolumeDiscount> VolumeDiscounts { get; set; } // VolumeDiscount
124127

125128
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
@@ -161,6 +164,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
161164
modelBuilder.ApplyConfiguration(new SalesByWeekConfiguration());
162165
modelBuilder.ApplyConfiguration(new SignatureUsedConfiguration());
163166
modelBuilder.ApplyConfiguration(new sys_DatabaseFirewallRuleConfiguration());
167+
modelBuilder.ApplyConfiguration(new TestingEfCore10Configuration());
164168
modelBuilder.ApplyConfiguration(new VolumeDiscountConfiguration());
165169
}
166170

@@ -740,6 +744,14 @@ public class sys_DatabaseFirewallRule
740744
public DateTime ModifyDate { get; set; } // modify_date
741745
}
742746

747+
// Testing_EfCore10
748+
public class TestingEfCore10
749+
{
750+
public int Id { get; set; } // Id (Primary key)
751+
public SqlVector<float>? Embedding { get; set; } // Embedding (length: 4944)
752+
public string ShippingAddress { get; set; } // ShippingAddress
753+
}
754+
743755
// VolumeDiscount
744756
public class VolumeDiscount
745757
{
@@ -1175,6 +1187,20 @@ public void Configure(EntityTypeBuilder<sys_DatabaseFirewallRule> builder)
11751187
}
11761188
}
11771189

1190+
// Testing_EfCore10
1191+
public class TestingEfCore10Configuration : IEntityTypeConfiguration<TestingEfCore10>
1192+
{
1193+
public void Configure(EntityTypeBuilder<TestingEfCore10> builder)
1194+
{
1195+
builder.ToTable("Testing_EfCore10", "dbo");
1196+
builder.HasKey(x => x.Id).HasName("PK_Testing_EfCore10").IsClustered();
1197+
1198+
builder.Property(x => x.Id).HasColumnName(@"Id").HasColumnType("int").IsRequired().ValueGeneratedOnAdd().UseIdentityColumn();
1199+
builder.Property(x => x.Embedding).HasColumnName(@"Embedding").HasColumnType("vector(4944)").IsRequired(false);
1200+
builder.Property(x => x.ShippingAddress).HasColumnName(@"ShippingAddress").HasColumnType("json").IsRequired();
1201+
}
1202+
}
1203+
11781204
// VolumeDiscount
11791205
public class VolumeDiscountConfiguration : IEntityTypeConfiguration<VolumeDiscount>
11801206
{

Tester.Integration.EFCore10/CustomersRepositoryTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ public class CustomersRepositoryTests
1212
{
1313
private MyDbContext _db = null!;
1414
private Dictionary<string, string> _dictionary = null!;
15-
//private IConfiguration _configuration;
1615

1716
[OneTimeSetUp]
1817
public void OneTimeSetUp()

0 commit comments

Comments
 (0)