Skip to content

Commit 334c2a7

Browse files
committed
Correctly support EFCore 10
1 parent ebc8f63 commit 334c2a7

32 files changed

+14966
-3446
lines changed

BuildTT/TemplateFiles.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ public static class TemplateFiles
1212
{
1313
public static void Create(string templatesRoot)
1414
{
15-
CreateFiles(new TemplateEf6(), Path.Combine(templatesRoot, "Templates.EF6"));
16-
CreateFiles(new TemplateEfCore8(), Path.Combine(templatesRoot, "Templates.EFCore8"));
17-
CreateFiles(new TemplateEfCore8(), Path.Combine(templatesRoot, "Templates.EFCore9"));
18-
CreateFiles(new TemplateEfCore10(), Path.Combine(templatesRoot, "Templates.EFCore10"));
15+
CreateFiles(new TemplateEf6(), Path.Combine(templatesRoot, "Templates.EF6"));
16+
CreateFiles(new TemplateEfCore8(), Path.Combine(templatesRoot, "Templates.EFCore8"));
17+
CreateFiles(new TemplateEfCore8(), Path.Combine(templatesRoot, "Templates.EFCore9"));
18+
CreateFiles(new TemplateEfCore8(), Path.Combine(templatesRoot, "Templates.EFCore10"));
1919
}
2020

2121
private static void CreateFiles(Template template, string folder)

EntityFramework.Reverse.POCO.Generator/Database.tt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// For help on the various Types below, please read https://github.com/sjh37/EntityFramework-Reverse-POCO-Code-First-Generator/wiki/Common-Settings.*Types-explained
1313
// The following entries are the only required settings.
1414
Settings.DatabaseType = DatabaseType.SqlServer; // SqlServer, SqlCe, SQLite, PostgreSQL. Coming next: MySql, Oracle
15-
Settings.TemplateType = TemplateType.EfCore10; // EfCore9, EfCore8, Ef6, FileBasedCore8-9. FileBased specify folder using Settings.TemplateFolder
15+
Settings.TemplateType = TemplateType.EfCore9; // EfCore9, EfCore8, Ef6, FileBasedCore8-9. FileBased specify folder using Settings.TemplateFolder
1616
Settings.GeneratorType = GeneratorType.EfCore; // EfCore, Ef6, Custom. Custom edit GeneratorCustom class to provide your own implementation
1717

1818
Settings.FileManagerType = FileManagerType.EfCore; // .NET Core project = EfCore; .NET 4.x project = VisualStudio; No output (testing only) = Null

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

Lines changed: 22 additions & 1717 deletions
Large diffs are not rendered by default.

Generator/Generator.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@
134134
<Compile Include="Readers\SQLiteDatabaseReader.cs" />
135135
<Compile Include="TemplateModels\Trigger.cs" />
136136
<Compile Include="Templates\TemplateEfCore8.cs" />
137-
<Compile Include="Templates\TemplateEfCore10.cs" />
138137
<Compile Include="Templates\TemplateFileBasedConstants.cs" />
139138
<Compile Include="Util\MultiContextSettingsCopy.cs" />
140139
<Compile Include="Filtering\PeriodFilter.cs" />

Generator/Generators/CodeGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +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)),
496497
Columns = columnsQuery
497498
.Where(x => !x.Hidden && !x.ExistsInBaseClass)
498499
.Select((col, index) => new PocoColumnModel

Generator/Generators/GeneratorEfCore.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,14 @@ protected override void SetupConfig(Column c)
104104
doNotSpecifySize = (DatabaseReader.DoNotSpecifySizeForMaxLength && c.MaxLength > 4000); // Issue #179
105105

106106
var excludedHasColumnType = string.Empty;
107+
var isVectorType = c.SqlPropertyType != null && c.SqlPropertyType.StartsWith("vector", StringComparison.InvariantCultureIgnoreCase);
107108
if (!string.IsNullOrEmpty(c.SqlPropertyType))
108109
{
109110
var columnTypeParameters = string.Empty;
110111

111112
if ((c.Precision > 0 || c.Scale > 0) && (c.SqlPropertyType == "decimal" || c.SqlPropertyType == "numeric"))
112113
columnTypeParameters = $"({c.Precision},{c.Scale})";
113-
else if (!c.IsMaxLength && c.MaxLength > 0 && !doNotSpecifySize)
114+
else if (!c.IsMaxLength && c.MaxLength > 0 && !doNotSpecifySize && !isVectorType) // Vector types already include dimension in SqlPropertyType
114115
columnTypeParameters = $"({c.MaxLength})";
115116

116117
if (Column.ExcludedHasColumnType.Contains(c.SqlPropertyType))
@@ -140,7 +141,7 @@ protected override void SetupConfig(Column c)
140141
if (!c.IsUnicode)
141142
sb.Append(".IsUnicode(false)");
142143

143-
if (!c.IsMaxLength && c.MaxLength > 0 && !doNotSpecifySize)
144+
if (!c.IsMaxLength && c.MaxLength > 0 && !doNotSpecifySize && !isVectorType) // Vector types use dimension in HasColumnType, not HasMaxLength
144145
sb.AppendFormat(".HasMaxLength({0})", c.MaxLength);
145146

146147
//if (c.IsMaxLength)

Generator/LanguageMapping/SqlServerToCSharp.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public Dictionary<string, string> GetMapping()
2828
{ "hierarchyid", "Hierarchy.HierarchyId" },
2929
{ "image", "byte[]" },
3030
{ "int", "int" },
31+
{ "json", "string" }, // SQL Server 2025 / Azure SQL native json type
3132
{ "money", "decimal" },
3233
{ "numeric", "decimal" },
3334
{ "real", "float" },
@@ -39,6 +40,7 @@ public Dictionary<string, string> GetMapping()
3940
{ "timestamp", "byte[]" },
4041
{ "tinyint", "byte" },
4142
{ "uniqueidentifier", "Guid" },
43+
{ "vector", "SqlVector<float>" }, // SQL Server 2025 / Azure SQL vector type for AI/ML (requires Microsoft.Data.SqlClient.Types namespace)
4244
{ "varbinary", "byte[]" },
4345
{ "varbinary(max)", "byte[]" }
4446
};

Generator/Readers/DatabaseReader.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ protected enum MemoryOptimised
6767
protected abstract bool HasTemporalTableSupport();
6868
public abstract bool HasIdentityColumnSupport();
6969

70+
/// <summary>
71+
/// Checks if the database supports SQL Server 2025 features (json and vector types).
72+
/// Returns false by default; overridden in SqlServerDatabaseReader.
73+
/// </summary>
74+
public virtual bool HasSqlServer2025TypeSupport() => false;
75+
7076
// Stored proc return objects
7177
public abstract void ReadStoredProcReturnObjects(List<StoredProcedure> procs);
7278

@@ -1118,6 +1124,12 @@ public Column CreateColumn(RawTable rt, Table table, IDbContextFilter filter)
11181124
col.SqlPropertyType += "(max)";
11191125
}
11201126

1127+
// SQL Server 2025 vector type - include dimension in SqlPropertyType for [Column(TypeName = "vector(n)")]
1128+
if (col.SqlPropertyType.Equals("vector", StringComparison.InvariantCultureIgnoreCase) && col.MaxLength > 0)
1129+
{
1130+
col.SqlPropertyType = $"vector({col.MaxLength})";
1131+
}
1132+
11211133
if (col.IsPrimaryKey && !col.IsIdentity && col.IsStoreGenerated && rt.TypeName == "uniqueidentifier")
11221134
{
11231135
col.IsStoreGenerated = false;

Generator/Readers/SqlServerDatabaseReader.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ public SqlServerDatabaseReader(DbProviderFactory factory, IDatabaseToPropertyTyp
5252
{ "date", "Date" },
5353
{ "time", "Time" },
5454
{ "datetime2", "DateTime2" },
55-
{ "datetimeoffset", "DateTimeOffset" }
55+
{ "datetimeoffset", "DateTimeOffset" },
56+
// SQL Server 2025 / Azure SQL types (SqlDbType mappings for stored procedure parameters)
57+
// Note: C# type mappings (string, SqlVector<float>) are defined in SqlServerToCSharp.cs
58+
{ "json", "NVarChar" }, // Native JSON type (SQL Server 2025+) -> maps to string in C#
59+
{ "vector", "VarBinary" } // Native vector type for AI/ML (SQL Server 2025+) -> maps to SqlVector<float> in C#
5660
};
5761
}
5862

@@ -1086,6 +1090,17 @@ protected override bool HasTemporalTableSupport()
10861090
return DatabaseProductMajorVersion >= 13;
10871091
}
10881092

1093+
/// <summary>
1094+
/// Checks if the database supports SQL Server 2025 features (json and vector types).
1095+
/// SQL Server 2025 = version 17, or Azure SQL Database with compatibility level 170+.
1096+
/// </summary>
1097+
public override bool HasSqlServer2025TypeSupport()
1098+
{
1099+
// SQL Server 2025 is version 17.x
1100+
// Azure SQL Database also supports these types
1101+
return DatabaseProductMajorVersion >= 17 || IsAzure();
1102+
}
1103+
10891104
public override bool HasIdentityColumnSupport()
10901105
{
10911106
return true;

Generator/Settings.cs

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ 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, automatically maps SQL Server 2025 vector and json types when using EFCore 10+
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)
8383

8484
// Language choices
8585
public static GenerationLanguage GenerationLanguage = GenerationLanguage.CSharp;
@@ -359,7 +359,13 @@ public static class Settings
359359
if (column.IsRowVersion)
360360
column.Attributes.Add("[Timestamp, ConcurrencyCheck]");
361361

362-
if (!column.IsMaxLength && column.MaxLength > 0)
362+
// SQL Server 2025 vector type - use [Column(TypeName = "vector(n)")] instead of MaxLength
363+
var isVectorType = column.SqlPropertyType != null && column.SqlPropertyType.StartsWith("vector", StringComparison.InvariantCultureIgnoreCase);
364+
if (isVectorType)
365+
{
366+
column.Attributes.Add(string.Format("[Column(TypeName = \"{0}\")]", column.SqlPropertyType));
367+
}
368+
else if (!column.IsMaxLength && column.MaxLength > 0)
363369
{
364370
var doNotSpecifySize = (DatabaseType == DatabaseType.SqlCe && column.MaxLength > 4000);
365371
column.Attributes.Add(doNotSpecifySize ? "[MaxLength]" : string.Format("[MaxLength({0})]", column.MaxLength));
@@ -378,32 +384,6 @@ public static class Settings
378384
column.Attributes.Add(string.Format("[Display(Name = \"{0}\")]", column.DisplayName));
379385
}
380386

381-
// SQL Server 2025 type mapping (EF Core 10+)
382-
if (AutoMapSqlServer2025Types && IsEfCore10Plus())
383-
{
384-
// Handle vector type (e.g., vector(1536))
385-
if (column.SqlPropertyType != null && column.SqlPropertyType.StartsWith("vector", StringComparison.OrdinalIgnoreCase))
386-
{
387-
column.PropertyType = "float[]"; // or "SqlVector<float>" if you prefer the SqlClient type
388-
// Uncomment the line below if using SqlVector<float>:
389-
// if (!AdditionalNamespaces.Contains("Microsoft.Data.SqlClient.Types"))
390-
// AdditionalNamespaces.Add("Microsoft.Data.SqlClient.Types");
391-
}
392-
393-
// Handle json type
394-
if (column.SqlPropertyType != null && column.SqlPropertyType.Equals("json", StringComparison.OrdinalIgnoreCase))
395-
{
396-
column.PropertyType = "string"; // Maps to string by default, can be JsonDocument or custom class
397-
// Alternative mappings:
398-
// column.PropertyType = "JsonDocument"; // Use System.Text.Json.JsonDocument
399-
// column.PropertyType = "JsonElement"; // Use System.Text.Json.JsonElement
400-
401-
// Uncomment if using JsonDocument or JsonElement:
402-
// if (!AdditionalNamespaces.Contains("System.Text.Json"))
403-
// AdditionalNamespaces.Add("System.Text.Json");
404-
}
405-
}
406-
407387
// Perform Enum property type replacement
408388
var enumDefinition = enumDefinitions?.FirstOrDefault(e =>
409389
(e.Schema.Equals(table.Schema.DbName, StringComparison.InvariantCultureIgnoreCase)) &&

0 commit comments

Comments
 (0)