Skip to content

Commit 73cdd1a

Browse files
committed
Scaffolding: retrieves BlobSegmentSize, CharacterSet, DomainName, IdentityType, IdentityStart and IdentityIncrement from database.
1 parent fa62ca2 commit 73cdd1a

File tree

4 files changed

+125
-46
lines changed

4 files changed

+125
-46
lines changed

src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Scaffolding/ScaffoldingTests.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515

1616
//$Authors = Jiri Cincura ([email protected])
1717

18+
using System;
1819
using System.Linq;
1920
using System.Threading.Tasks;
21+
using FirebirdSql.EntityFrameworkCore.Firebird.Metadata.Internal;
2022
using FirebirdSql.EntityFrameworkCore.Firebird.Scaffolding.Internal;
2123
using Microsoft.EntityFrameworkCore.Scaffolding;
2224
using Microsoft.EntityFrameworkCore.Scaffolding.Metadata;
@@ -51,26 +53,39 @@ public void CanScaffoldColumns()
5153
var testTable = _databaseModel.Tables.Where(t => t.Name == "TEST").First();
5254
Assert.NotNull(testTable);
5355

56+
var intColumn = testTable.Columns.Where(c => c.Name == "INT_FIELD").First();
57+
Assert.AreEqual("INTEGER", intColumn.StoreType);
58+
Assert.AreEqual("1", intColumn.DefaultValueSql);
59+
5460
var charColumn = testTable.Columns.Where(c => c.Name == "CHAR_FIELD").First();
5561
Assert.AreEqual("CHAR(30)", charColumn.StoreType);
5662

5763
var varcharColumn = testTable.Columns.Where(c => c.Name == "VARCHAR_FIELD").First();
5864
Assert.AreEqual("VARCHAR(100)", varcharColumn.StoreType);
5965

60-
var csColumn = testTable.Columns.Where(c => c.Name == "CS_FIELD").First();
61-
Assert.AreEqual("CHAR(1)", csColumn.StoreType);
62-
Assert.AreEqual("UNICODE_FSS", csColumn.Collation);
63-
6466
var numericColumn = testTable.Columns.Where(c => c.Name == "NUMERIC_FIELD").First();
6567
Assert.AreEqual("NUMERIC(15,2)", numericColumn.StoreType);
6668

6769
var decimalColumn = testTable.Columns.Where(c => c.Name == "DECIMAL_FIELD").First();
6870
Assert.AreEqual("DECIMAL(15,2)", decimalColumn.StoreType);
6971

72+
var blobColumn = testTable.Columns.Where(c => c.Name == "BLOB_FIELD").First();
73+
Assert.AreEqual("BLOB SUB_TYPE BINARY", blobColumn.StoreType);
74+
Assert.AreEqual(80, Convert.ToInt32(blobColumn.GetAnnotation(FbAnnotationNames.BlobSegmentSize).Value));
75+
76+
var clobColumn = testTable.Columns.Where(c => c.Name == "CLOB_FIELD").First();
77+
Assert.AreEqual("BLOB SUB_TYPE TEXT", clobColumn.StoreType);
78+
Assert.AreEqual(80, Convert.ToInt32(clobColumn.GetAnnotation(FbAnnotationNames.BlobSegmentSize).Value));
79+
7080
var exprColumn = testTable.Columns.Where(c => c.Name == "EXPR_FIELD").First();
7181
Assert.AreEqual("(smallint_field * 1000)", exprColumn.ComputedColumnSql);
82+
83+
var csColumn = testTable.Columns.Where(c => c.Name == "CS_FIELD").First();
84+
Assert.AreEqual("CHAR(1)", csColumn.StoreType);
85+
Assert.AreEqual("UNICODE_FSS", csColumn.Collation);
86+
Assert.AreEqual("UNICODE_FSS", csColumn.GetAnnotation(FbAnnotationNames.CharacterSet).Value.ToString());
7287
}
73-
88+
7489
private static IDatabaseModelFactory GetModelFactory()
7590
{
7691
return new FbDatabaseModelFactory();
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* The contents of this file are subject to the Initial
3+
* Developer's Public License Version 1.0 (the "License");
4+
* you may not use this file except in compliance with the
5+
* License. You may obtain a copy of the License at
6+
* https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt.
7+
*
8+
* Software distributed under the License is distributed on
9+
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
10+
* express or implied. See the License for the specific
11+
* language governing rights and limitations under the License.
12+
*
13+
* All Rights Reserved.
14+
*/
15+
16+
//$Authors = Jiri Cincura ([email protected]), Jean Ressouche, Rafael Almeida ([email protected])
17+
18+
namespace FirebirdSql.EntityFrameworkCore.Firebird.Metadata;
19+
20+
public enum FbIdentityType
21+
{
22+
GeneratedAlways = 0,
23+
GeneratedByDefault = 1,
24+
}

src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Internal/FbAnnotationNames.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,14 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.Metadata.Internal;
2020
public static class FbAnnotationNames
2121
{
2222
public const string Prefix = "Fb:";
23+
2324
public const string ValueGenerationStrategy = Prefix + nameof(ValueGenerationStrategy);
25+
26+
public const string BlobSegmentSize = Prefix + nameof(BlobSegmentSize);
27+
public const string CharacterSet = Prefix + nameof(CharacterSet);
28+
public const string DomainName = Prefix + nameof(DomainName);
29+
30+
public const string IdentityType = Prefix + nameof(IdentityType);
31+
public const string IdentityStart = Prefix + nameof(IdentityStart);
32+
public const string IdentityIncrement = Prefix + nameof(IdentityIncrement);
2433
}

src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Linq;
2323
using FirebirdSql.Data.FirebirdClient;
2424
using FirebirdSql.Data.Services;
25+
using FirebirdSql.EntityFrameworkCore.Firebird.Metadata.Internal;
2526
using Microsoft.EntityFrameworkCore.Metadata;
2627
using Microsoft.EntityFrameworkCore.Migrations;
2728
using Microsoft.EntityFrameworkCore.Scaffolding;
@@ -142,11 +143,13 @@ private IEnumerable<DatabaseTable> GetTables(DbConnection connection, Func<Datab
142143
}
143144
}
144145

145-
private const string GetColumnsQuery = @"
146+
private void GetColumns(DbConnection connection, IReadOnlyList<DatabaseTable> tables, Func<DatabaseTable, bool> tableFilter)
147+
{
148+
var getColumnsQuery = $@"
146149
SELECT
147150
rf.rdb$field_name COLUMN_NAME,
148-
COALESCE(rf.rdb$default_source, f.rdb$default_source) COLUMN_DEFAULT,
149151
COALESCE(rf.rdb$null_flag, 0) COLUMN_REQUIRED,
152+
150153
CASE COALESCE(f.rdb$field_type, 0)
151154
WHEN 7 THEN CASE f.rdb$field_sub_type
152155
WHEN 1 THEN 'NUMERIC'
@@ -181,48 +184,66 @@ ELSE f.rdb$field_sub_type
181184
END
182185
ELSE 'RDB$FIELD_TYPE: ' || F.RDB$FIELD_TYPE || '?'
183186
END COLUMN_STORE_TYPE,
187+
188+
rf.rdb$field_source COLUMN_DOMAIN,
184189
COALESCE(F.rdb$character_length, 0) COLUMN_LENGTH,
185190
COALESCE(F.rdb$field_precision, 0) COLUMN_PRECISION,
186191
COALESCE(-F.rdb$field_scale, 0) COLUMN_SCALE,
192+
193+
NULLIF(ch.rdb$character_set_name, d.rdb$character_set_name) as CHARACTER_SET_NAME,
194+
co.rdb$collation_name COLLATION_NAME,
195+
COALESCE(f.rdb$segment_length, 0) SEGMENT_LENGTH,
196+
197+
COALESCE(rf.rdb$default_source, f.rdb$default_source) COLUMN_DEFAULT,
187198
f.rdb$computed_source COLUMN_COMPUTED_SOURCE,
188199
f.rdb$description COLUMN_COMMENT,
189-
COALESCE({0}, -1) IDENTITY_TYPE,
190-
ch.rdb$character_set_name as CHARACTER_SET_NAME,
191-
co.rdb$collation_name COLLATION_NAME
200+
201+
COALESCE({(MajorVersionNumber < 3 ? "NULL" : "rf.rdb$identity_type")}, -1) IDENTITY_TYPE,
202+
COALESCE({(MajorVersionNumber < 3 ? "NULL" : "g.rdb$initial_value")}, 1) IDENTITY_START,
203+
COALESCE({(MajorVersionNumber < 3 ? "NULL" : "g.rdb$generator_increment")}, 1) IDENTITY_INCREMENT
192204
FROM
193205
rdb$relation_fields rf
194206
JOIN rdb$fields f ON f.rdb$field_name = rf.rdb$field_source
195-
LEFT OUTER JOIN rdb$character_sets ch ON ch.rdb$character_set_id = f.rdb$character_set_id
196-
LEFT OUTER JOIN rdb$collations co ON co.rdb$character_set_id = f.rdb$character_set_id AND co.rdb$collation_id = rf.rdb$collation_id
207+
LEFT JOIN rdb$character_sets ch ON ch.rdb$character_set_id = f.rdb$character_set_id
208+
LEFT JOIN rdb$collations co ON co.rdb$character_set_id = f.rdb$character_set_id AND co.rdb$collation_id = rf.rdb$collation_id
209+
{(MajorVersionNumber < 3 ? "" : "LEFT JOIN rdb$generators g ON g.rdb$generator_name = rf.rdb$generator_name")}
210+
CROSS JOIN rdb$database d
197211
WHERE
198212
TRIM(rf.rdb$relation_name) = @pRelationName AND COALESCE(rf.rdb$system_flag, 0) = 0
199213
ORDER BY
200214
rf.rdb$field_position";
201215

202-
private void GetColumns(DbConnection connection, IReadOnlyList<DatabaseTable> tables, Func<DatabaseTable, bool> tableFilter)
203-
{
204-
var identityType = MajorVersionNumber < 3 ? "NULL" : "rf.rdb$identity_type";
205-
206216
foreach (var table in tables)
207217
{
208218
using (var command = connection.CreateCommand())
209219
{
210-
command.CommandText = string.Format(GetColumnsQuery, identityType);
220+
command.CommandText = getColumnsQuery;
211221
command.Parameters.Add(new FbParameter("@pRelationName", table.Name));
212222
using (var reader = command.ExecuteReader())
213223
{
214224
while (reader.Read())
215225
{
216226
var name = reader["COLUMN_NAME"].ToString();
217-
var defaultValue = reader["COLUMN_DEFAULT"].ToString();
218-
var nullable = !Convert.ToBoolean(reader["COLUMN_REQUIRED"]);
219-
var autoGenerated = Convert.ToInt32(reader["IDENTITY_TYPE"]);
227+
var isNullable = !Convert.ToBoolean(reader["COLUMN_REQUIRED"]);
228+
var storeType = reader["COLUMN_STORE_TYPE"].ToString();
229+
230+
var columnDomain = reader["COLUMN_DOMAIN"].ToString();
220231
var columnLength = Convert.ToInt32(reader["COLUMN_LENGTH"]);
221232
var columnPrecision = Convert.ToInt32(reader["COLUMN_PRECISION"]);
222233
var columnScale = Convert.ToInt32(reader["COLUMN_SCALE"]);
223-
var computedSource = reader["COLUMN_COMPUTED_SOURCE"].ToString();
224234

225-
var storeType = reader["COLUMN_STORE_TYPE"].ToString();
235+
var charset = reader["CHARACTER_SET_NAME"].ToString();
236+
var collation = reader["COLLATION_NAME"].ToString();
237+
var segmentSize = Convert.ToInt32(reader["SEGMENT_LENGTH"]);
238+
239+
var defaultValue = reader["COLUMN_DEFAULT"].ToString();
240+
var computedSource = reader["COLUMN_COMPUTED_SOURCE"].ToString();
241+
var comment = reader["COLUMN_COMMENT"].ToString();
242+
243+
var identityType = Convert.ToInt32(reader["IDENTITY_TYPE"]);
244+
var identityStart = Convert.ToInt32(reader["IDENTITY_START"]);
245+
var identityIncrement = Convert.ToInt32(reader["IDENTITY_INCREMENT"]);
246+
226247
storeType = storeType switch
227248
{
228249
"CHAR" or
@@ -235,47 +256,57 @@ private void GetColumns(DbConnection connection, IReadOnlyList<DatabaseTable> ta
235256
_ => storeType
236257
};
237258

238-
var charset = reader["CHARACTER_SET_NAME"].ToString();
239-
var collation = reader["COLLATION_NAME"].ToString();
240-
var comment = reader["COLUMN_COMMENT"].ToString();
241-
242259
var column = new DatabaseColumn
243260
{
244261
Table = table,
245262
Name = name.Trim(),
246263
StoreType = storeType,
247-
IsNullable = nullable,
248-
DefaultValueSql = CreateDefaultValueString(defaultValue),
249-
ValueGenerated = autoGenerated == -1 ? ValueGenerated.Never : ValueGenerated.OnAdd,
264+
IsNullable = isNullable,
265+
266+
DefaultValueSql = string.IsNullOrEmpty(defaultValue) ? null : defaultValue.Remove(0, 8),
267+
ValueGenerated = identityType == -1 ? ValueGenerated.Never : ValueGenerated.OnAdd,
250268
Comment = string.IsNullOrEmpty(comment) ? null : comment,
251269
Collation = string.IsNullOrEmpty(collation) ? null : collation.Trim(),
252270
ComputedColumnSql = string.IsNullOrEmpty(computedSource) ? null : computedSource
253271
};
254272

273+
if (segmentSize > 0)
274+
{
275+
column.SetAnnotation(FbAnnotationNames.BlobSegmentSize, segmentSize);
276+
}
277+
278+
if (!string.IsNullOrEmpty(charset))
279+
{
280+
column.SetAnnotation(FbAnnotationNames.CharacterSet, charset.Trim());
281+
}
282+
283+
if (!columnDomain.StartsWith("RDB$"))
284+
{
285+
column.SetAnnotation(FbAnnotationNames.DomainName, columnDomain);
286+
}
287+
288+
if (identityType != -1)
289+
{
290+
column.SetAnnotation(FbAnnotationNames.IdentityType, identityType);
291+
}
292+
293+
if (identityStart != 1)
294+
{
295+
column.SetAnnotation(FbAnnotationNames.IdentityStart, identityStart);
296+
}
297+
298+
if (identityIncrement != 1)
299+
{
300+
column.SetAnnotation(FbAnnotationNames.IdentityIncrement, identityIncrement);
301+
}
302+
255303
table.Columns.Add(column);
256304
}
257305
}
258306
}
259307
}
260308
}
261309

262-
private string CreateDefaultValueString(string defaultValue)
263-
{
264-
if (defaultValue == null)
265-
{
266-
return null;
267-
}
268-
if (defaultValue.StartsWith("default "))
269-
{
270-
return defaultValue.Remove(0, 8);
271-
}
272-
else
273-
{
274-
return null;
275-
}
276-
277-
}
278-
279310
private const string GetPrimaryQuery =
280311
@"SELECT
281312
trim(i.rdb$index_name) as INDEX_NAME,

0 commit comments

Comments
 (0)