diff --git a/README.md b/README.md index fe628db..d3be8f2 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ The following features are supported: - Index (Decorate columns with the `Index` attribute. Indices are automatically created for foreign keys by default. To prevent this you can remove the convention `ForeignKeyIndexConvention`) - Unique constraint (Decorate columns with the `UniqueAttribute`, which is part of this library) - Collate constraint (Decorate columns with the `CollateAttribute`, which is part of this library. Use `CollationFunction.Custom` to specify a own collation function.) +- Default collation (pass an instance of Collation as constructor parameter for an initializer to specify a default collation). - SQL default value (Decorate columns with the `SqlDefaultValueAttribute`, which is part of this library) ## Install diff --git a/SQLite.CodeFirst.Test/IntegrationTests/SqlGenerationDefaultCollationTest.cs b/SQLite.CodeFirst.Test/IntegrationTests/SqlGenerationDefaultCollationTest.cs new file mode 100644 index 0000000..d6cbd08 --- /dev/null +++ b/SQLite.CodeFirst.Test/IntegrationTests/SqlGenerationDefaultCollationTest.cs @@ -0,0 +1,118 @@ +using System.Data.Common; +using System.Data.Entity; +using System.Data.Entity.Infrastructure; +using System.Data.SQLite; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SQLite.CodeFirst.Console; +using SQLite.CodeFirst.Console.Entity; + +namespace SQLite.CodeFirst.Test.IntegrationTests +{ + [TestClass] + public class SqlGenerationDefaultCollationTest + { + private const string ReferenceSql = + @" +CREATE TABLE ""MyTable"" ([Id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [Name] nvarchar NOT NULL COLLATE custom_collate, FOREIGN KEY ([Id]) REFERENCES ""Coaches""([Id])); +CREATE TABLE ""Coaches"" ([Id] INTEGER PRIMARY KEY, [FirstName] nvarchar (50) COLLATE NOCASE, [LastName] nvarchar (50) COLLATE custom_collate, [Street] nvarchar (100) COLLATE custom_collate, [City] nvarchar NOT NULL COLLATE custom_collate, [CreatedUtc] datetime NOT NULL DEFAULT (DATETIME('now'))); +CREATE TABLE ""TeamPlayer"" ([Id] INTEGER PRIMARY KEY, [Number] int NOT NULL, [TeamId] int NOT NULL, [FirstName] nvarchar (50) COLLATE NOCASE, [LastName] nvarchar (50) COLLATE custom_collate, [Street] nvarchar (100) COLLATE custom_collate, [City] nvarchar NOT NULL COLLATE custom_collate, [CreatedUtc] datetime NOT NULL DEFAULT (DATETIME('now')), [Mentor_Id] int, FOREIGN KEY ([Mentor_Id]) REFERENCES ""TeamPlayer""([Id]), FOREIGN KEY ([TeamId]) REFERENCES ""MyTable""([Id]) ON DELETE CASCADE); +CREATE TABLE ""Stadions"" ([Name] nvarchar (128) NOT NULL COLLATE custom_collate, [Street] nvarchar (128) NOT NULL COLLATE custom_collate, [City] nvarchar (128) NOT NULL COLLATE custom_collate, [Order] int NOT NULL, [Team_Id] int NOT NULL, PRIMARY KEY([Name], [Street], [City]), FOREIGN KEY ([Team_Id]) REFERENCES ""MyTable""([Id]) ON DELETE CASCADE); +CREATE TABLE ""Foos"" ([FooId] INTEGER PRIMARY KEY, [Name] nvarchar COLLATE custom_collate, [FooSelf1Id] int, [FooSelf2Id] int, [FooSelf3Id] int, FOREIGN KEY ([FooSelf1Id]) REFERENCES ""Foos""([FooId]), FOREIGN KEY ([FooSelf2Id]) REFERENCES ""Foos""([FooId]), FOREIGN KEY ([FooSelf3Id]) REFERENCES ""Foos""([FooId])); +CREATE TABLE ""FooSelves"" ([FooSelfId] INTEGER PRIMARY KEY, [FooId] int NOT NULL, [Number] int NOT NULL, FOREIGN KEY ([FooId]) REFERENCES ""Foos""([FooId]) ON DELETE CASCADE); +CREATE TABLE ""FooSteps"" ([FooStepId] INTEGER PRIMARY KEY, [FooId] int NOT NULL, [Number] int NOT NULL, FOREIGN KEY ([FooId]) REFERENCES ""Foos""([FooId]) ON DELETE CASCADE); +CREATE TABLE ""FooCompositeKeys"" ([Id] int NOT NULL, [Version] nvarchar (20) NOT NULL COLLATE custom_collate, [Name] nvarchar (255) COLLATE custom_collate, PRIMARY KEY([Id], [Version])); +CREATE TABLE ""FooRelationshipAs"" ([Id] INTEGER PRIMARY KEY, [Name] nvarchar (255) COLLATE custom_collate); +CREATE TABLE ""FooRelationshipBs"" ([Id] INTEGER PRIMARY KEY, [Name] nvarchar (255) COLLATE custom_collate); +CREATE TABLE ""FooRelationshipAFooCompositeKeys"" ([FooRelationshipA_Id] int NOT NULL, [FooCompositeKey_Id] int NOT NULL, [FooCompositeKey_Version] nvarchar (20) NOT NULL COLLATE custom_collate, PRIMARY KEY([FooRelationshipA_Id], [FooCompositeKey_Id], [FooCompositeKey_Version]), FOREIGN KEY ([FooRelationshipA_Id]) REFERENCES ""FooRelationshipAs""([Id]) ON DELETE CASCADE, FOREIGN KEY ([FooCompositeKey_Id], [FooCompositeKey_Version]) REFERENCES ""FooCompositeKeys""([Id], [Version]) ON DELETE CASCADE); +CREATE TABLE ""FooRelationshipBFooCompositeKeys"" ([FooRelationshipB_Id] int NOT NULL, [FooCompositeKey_Id] int NOT NULL, [FooCompositeKey_Version] nvarchar (20) NOT NULL COLLATE custom_collate, PRIMARY KEY([FooRelationshipB_Id], [FooCompositeKey_Id], [FooCompositeKey_Version]), FOREIGN KEY ([FooRelationshipB_Id]) REFERENCES ""FooRelationshipBs""([Id]) ON DELETE CASCADE, FOREIGN KEY ([FooCompositeKey_Id], [FooCompositeKey_Version]) REFERENCES ""FooCompositeKeys""([Id], [Version]) ON DELETE CASCADE); +CREATE INDEX ""IX_MyTable_Id"" ON ""MyTable"" (""Id""); +CREATE INDEX ""IX_Team_TeamsName"" ON ""MyTable"" (""Name""); +CREATE INDEX ""IX_TeamPlayer_Number"" ON ""TeamPlayer"" (""Number""); +CREATE UNIQUE INDEX ""IX_TeamPlayer_NumberPerTeam"" ON ""TeamPlayer"" (""Number"", ""TeamId""); +CREATE INDEX ""IX_TeamPlayer_Mentor_Id"" ON ""TeamPlayer"" (""Mentor_Id""); +CREATE UNIQUE INDEX ""IX_Stadion_Main"" ON ""Stadions"" (""Street"", ""Name""); +CREATE UNIQUE INDEX ""ReservedKeyWordTest"" ON ""Stadions"" (""Order""); +CREATE INDEX ""IX_Stadion_Team_Id"" ON ""Stadions"" (""Team_Id""); +CREATE INDEX ""IX_Foo_FooSelf1Id"" ON ""Foos"" (""FooSelf1Id""); +CREATE INDEX ""IX_Foo_FooSelf2Id"" ON ""Foos"" (""FooSelf2Id""); +CREATE INDEX ""IX_Foo_FooSelf3Id"" ON ""Foos"" (""FooSelf3Id""); +CREATE INDEX ""IX_FooSelf_FooId"" ON ""FooSelves"" (""FooId""); +CREATE INDEX ""IX_FooStep_FooId"" ON ""FooSteps"" (""FooId""); +CREATE INDEX ""IX_FooRelationshipAFooCompositeKey_FooRelationshipA_Id"" ON ""FooRelationshipAFooCompositeKeys"" (""FooRelationshipA_Id""); +CREATE INDEX ""IX_FooRelationshipAFooCompositeKey_FooCompositeKey_Id_FooCompositeKey_Version"" ON ""FooRelationshipAFooCompositeKeys"" (""FooCompositeKey_Id"", ""FooCompositeKey_Version""); +CREATE INDEX ""IX_FooRelationshipBFooCompositeKey_FooRelationshipB_Id"" ON ""FooRelationshipBFooCompositeKeys"" (""FooRelationshipB_Id""); +CREATE INDEX ""IX_FooRelationshipBFooCompositeKey_FooCompositeKey_Id_FooCompositeKey_Version"" ON ""FooRelationshipBFooCompositeKeys"" (""FooCompositeKey_Id"", ""FooCompositeKey_Version""); +"; + + private static string generatedSql; + + // Does not work on the build server. No clue why. + + [TestMethod] + public void SqliteSqlGeneratorWithDefaultCollationTest() + { + using (DbConnection connection = new SQLiteConnection("FullUri=file::memory:")) + { + // This is important! Else the in memory database will not work. + connection.Open(); + + var defaultCollation = new Collation() { Function = CollationFunction.Custom, CustomFunction = "custom_collate" }; + using (var context = new DummyDbContext(connection, defaultCollation)) + { + // ReSharper disable once UnusedVariable + Player fo = context.Set().FirstOrDefault(); + + Assert.AreEqual(RemoveLineEndings(ReferenceSql), RemoveLineEndings(generatedSql)); + } + } + } + + private static string RemoveLineEndings(string input) + { + string lineSeparator = ((char)0x2028).ToString(); + string paragraphSeparator = ((char)0x2029).ToString(); + return input.Replace("\r\n", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty).Replace(lineSeparator, string.Empty).Replace(paragraphSeparator, string.Empty); + } + + private class DummyDbContext : DbContext + { + private readonly Collation defaultCollation; + + public DummyDbContext(DbConnection connection, Collation defaultCollation = null) + : base(connection, false) + { + this.defaultCollation = defaultCollation; + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + // This configuration contains all supported cases. + // So it makes a perfect test to validate whether the + // generated SQL is correct. + ModelConfiguration.Configure(modelBuilder); + var initializer = new AssertInitializer(modelBuilder, defaultCollation); + Database.SetInitializer(initializer); + } + + private class AssertInitializer : SqliteInitializerBase + { + private readonly Collation defaultCollation; + + public AssertInitializer(DbModelBuilder modelBuilder, Collation defaultCollation) + : base(modelBuilder) + { + this.defaultCollation = defaultCollation; + } + + public override void InitializeDatabase(DummyDbContext context) + { + DbModel model = ModelBuilder.Build(context.Database.Connection); + var sqliteSqlGenerator = new SqliteSqlGenerator(defaultCollation); + generatedSql = sqliteSqlGenerator.Generate(model.StoreModel); + base.InitializeDatabase(context); + } + } + } + } +} \ No newline at end of file diff --git a/SQLite.CodeFirst/Internal/Builder/ColumnStatementCollectionBuilder.cs b/SQLite.CodeFirst/Internal/Builder/ColumnStatementCollectionBuilder.cs index 93043c2..3fba1bb 100644 --- a/SQLite.CodeFirst/Internal/Builder/ColumnStatementCollectionBuilder.cs +++ b/SQLite.CodeFirst/Internal/Builder/ColumnStatementCollectionBuilder.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Data.Entity.Core.Metadata.Edm; using System.Linq; using SQLite.CodeFirst.Extensions; @@ -11,11 +12,13 @@ internal class ColumnStatementCollectionBuilder : IStatementBuilder properties; private readonly IEnumerable keyMembers; + private readonly Collation defaultCollation; - public ColumnStatementCollectionBuilder(IEnumerable properties, IEnumerable keyMembers) + public ColumnStatementCollectionBuilder(IEnumerable properties, IEnumerable keyMembers, Collation defaultCollation) { this.properties = properties; this.keyMembers = keyMembers; + this.defaultCollation = defaultCollation; } public ColumnStatementCollection BuildStatement() @@ -39,7 +42,7 @@ private IEnumerable CreateColumnStatements() AdjustDatatypeForAutogenerationIfNecessary(property, columnStatement); AddNullConstraintIfNecessary(property, columnStatement); AddUniqueConstraintIfNecessary(property, columnStatement); - AddCollationConstraintIfNecessary(property, columnStatement); + AddCollationConstraintIfNecessary(property, columnStatement, defaultCollation); AddPrimaryKeyConstraintAndAdjustTypeIfNecessary(property, columnStatement); AddDefaultValueConstraintIfNecessary(property, columnStatement); @@ -73,12 +76,25 @@ private static void AddNullConstraintIfNecessary(EdmProperty property, ColumnSta } } - private static void AddCollationConstraintIfNecessary(EdmProperty property, ColumnStatement columnStatement) + private static void AddCollationConstraintIfNecessary(EdmProperty property, ColumnStatement columnStatement, Collation defaultCollation) { - var value = property.GetCustomAnnotation(); - if (value != null) + var collateAttribute = property.GetCustomAnnotation(); + if (property.PrimitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String) + { + // The column is a string type. Check if we have an explicit or default collation. + // If we have both, the explicitly chosen collation takes precedence. + var value = collateAttribute == null ? defaultCollation : collateAttribute.Collation; + if (value != null) + { + columnStatement.ColumnConstraints.Add(new CollateConstraint { CollationFunction = value.Function, CustomCollationFunction = value.CustomFunction }); + } + } + else if (collateAttribute != null) { - columnStatement.ColumnConstraints.Add(new CollateConstraint { CollationFunction = value.Collation, CustomCollationFunction = value.Function }); + // Only string columns can be explicitly decorated with CollateAttribute. + var name = $"{property.DeclaringType.Name}.{property.Name}"; + var errorMessage = $"CollateAttribute cannot be used on non-string property: {name} (underlying type is {property.PrimitiveType.PrimitiveTypeKind})"; + throw new InvalidOperationException(errorMessage); } } diff --git a/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs b/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs index 65862a2..ea87cca 100644 --- a/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs +++ b/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs @@ -9,10 +9,12 @@ namespace SQLite.CodeFirst.Builder internal class CreateDatabaseStatementBuilder : IStatementBuilder { private readonly EdmModel edmModel; + private readonly Collation defaultCollation; - public CreateDatabaseStatementBuilder(EdmModel edmModel) + public CreateDatabaseStatementBuilder(EdmModel edmModel, Collation defaultCollation) { this.edmModel = edmModel; + this.defaultCollation = defaultCollation; } public CreateDatabaseStatement BuildStatement() @@ -30,7 +32,7 @@ private IEnumerable GetCreateTableStatements() foreach (var entitySet in edmModel.Container.EntitySets) { - var tableStatementBuilder = new CreateTableStatementBuilder(entitySet, associationTypeContainer); + var tableStatementBuilder = new CreateTableStatementBuilder(entitySet, associationTypeContainer, defaultCollation); yield return tableStatementBuilder.BuildStatement(); } } diff --git a/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs b/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs index b86f701..ac3198b 100644 --- a/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs +++ b/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs @@ -12,11 +12,13 @@ internal class CreateTableStatementBuilder : IStatementBuilder(); diff --git a/SQLite.CodeFirst/Public/Attributes/CollateAttribute.cs b/SQLite.CodeFirst/Public/Attributes/CollateAttribute.cs index 2dfc272..636965a 100644 --- a/SQLite.CodeFirst/Public/Attributes/CollateAttribute.cs +++ b/SQLite.CodeFirst/Public/Attributes/CollateAttribute.cs @@ -12,39 +12,19 @@ public sealed class CollateAttribute : Attribute { public CollateAttribute() { - Collation = CollationFunction.None; + Collation = new Collation(); } - public CollateAttribute(CollationFunction collation) + public CollateAttribute(CollationFunction function) { - if (collation == CollationFunction.Custom) - { - throw new ArgumentException("If the collation is set to CollationFunction.Custom a function must be specified.", nameof(collation)); - } - - Collation = collation; + Collation = new Collation(function); } - public CollateAttribute(CollationFunction collation, string function) - { - if (collation != CollationFunction.Custom && !string.IsNullOrEmpty(function)) - { - throw new ArgumentException("If the collation is not set to CollationFunction.Custom a function must not be specified.", nameof(function)); - } - - if (collation == CollationFunction.Custom && string.IsNullOrEmpty(function)) - { - throw new ArgumentException("If the collation is set to CollationFunction.Custom a function must be specified.", nameof(function)); - } - Collation = collation; - Function = function; + public CollateAttribute(CollationFunction function, string customFunction) + { + Collation = new Collation(function, customFunction); } - public CollationFunction Collation { get; } - - /// - /// The name of the custom collating function to use (CollationFunction.Custom). - /// - public string Function { get; } + public Collation Collation { get; } } } \ No newline at end of file diff --git a/SQLite.CodeFirst/Public/Collation.cs b/SQLite.CodeFirst/Public/Collation.cs new file mode 100644 index 0000000..0695e73 --- /dev/null +++ b/SQLite.CodeFirst/Public/Collation.cs @@ -0,0 +1,46 @@ +using System; + +namespace SQLite.CodeFirst +{ + /// + /// This class can be used to specify the default collation for the database. Explicit Collate attributes will take precendence. + /// When SQLite compares two strings, it uses a collating sequence or collating function (two words for the same thing) + /// to determine which string is greater or if the two strings are equal. SQLite has three built-in collating functions (see ). + /// Set to and specify the name using the function parameter. + /// + public class Collation + { + public Collation() + : this(CollationFunction.None) + { + } + + public Collation(CollationFunction function) + : this(function, null) + { + } + + public Collation(CollationFunction function, string customFunction) + { + if (function != CollationFunction.Custom && !string.IsNullOrEmpty(customFunction)) + { + throw new ArgumentException("If the collation is not set to CollationFunction.Custom a function must not be specified.", nameof(function)); + } + + if (function == CollationFunction.Custom && string.IsNullOrEmpty(customFunction)) + { + throw new ArgumentException("If the collation is set to CollationFunction.Custom a function must be specified.", nameof(function)); + } + + CustomFunction = customFunction; + Function = function; + } + + public CollationFunction Function { get; set; } + + /// + /// The name of the custom collating function to use (CollationFunction.Custom). + /// + public string CustomFunction { get; set; } + } +} diff --git a/SQLite.CodeFirst/Public/Attributes/CollationFunction.cs b/SQLite.CodeFirst/Public/CollationFunction.cs similarity index 95% rename from SQLite.CodeFirst/Public/Attributes/CollationFunction.cs rename to SQLite.CodeFirst/Public/CollationFunction.cs index 1bb7f30..6bd054d 100644 --- a/SQLite.CodeFirst/Public/Attributes/CollationFunction.cs +++ b/SQLite.CodeFirst/Public/CollationFunction.cs @@ -2,7 +2,7 @@ { /// /// The collation function to use for this column. - /// Is used together with the . + /// Is used together with the , and when setting a default collation for the database. /// public enum CollationFunction { diff --git a/SQLite.CodeFirst/Public/DbInitializers/SqliteDropCreateDatabaseWhenModelChanges.cs b/SQLite.CodeFirst/Public/DbInitializers/SqliteDropCreateDatabaseWhenModelChanges.cs index d83c3a9..f8029fc 100644 --- a/SQLite.CodeFirst/Public/DbInitializers/SqliteDropCreateDatabaseWhenModelChanges.cs +++ b/SQLite.CodeFirst/Public/DbInitializers/SqliteDropCreateDatabaseWhenModelChanges.cs @@ -172,7 +172,7 @@ private string GetHashFromModel(DbConnection connection) private string GetSqlFromModel(DbConnection connection) { var model = ModelBuilder.Build(connection); - var sqliteSqlGenerator = new SqliteSqlGenerator(); + var sqliteSqlGenerator = new SqliteSqlGenerator(DefaultCollation); return sqliteSqlGenerator.Generate(model.StoreModel); } } diff --git a/SQLite.CodeFirst/Public/DbInitializers/SqliteInitializerBase.cs b/SQLite.CodeFirst/Public/DbInitializers/SqliteInitializerBase.cs index a84cdf8..1309b1f 100644 --- a/SQLite.CodeFirst/Public/DbInitializers/SqliteInitializerBase.cs +++ b/SQLite.CodeFirst/Public/DbInitializers/SqliteInitializerBase.cs @@ -24,9 +24,10 @@ namespace SQLite.CodeFirst public abstract class SqliteInitializerBase : IDatabaseInitializer where TContext : DbContext { - protected SqliteInitializerBase(DbModelBuilder modelBuilder) + protected SqliteInitializerBase(DbModelBuilder modelBuilder, Collation defaultCollation = null) { ModelBuilder = modelBuilder ?? throw new ArgumentNullException(nameof(modelBuilder)); + DefaultCollation = defaultCollation; // This convention will crash the SQLite Provider before "InitializeDatabase" gets called. // See https://github.com/msallin/SQLiteCodeFirst/issues/7 for details. @@ -55,6 +56,8 @@ protected SqliteInitializerBase(DbModelBuilder modelBuilder) } } + public Collation DefaultCollation { get; } + protected DbModelBuilder ModelBuilder { get; } /// @@ -71,7 +74,7 @@ public virtual void InitializeDatabase(TContext context) string dbFile = GetDatabasePathFromContext(context); InMemoryAwareFile.CreateDirectory(dbFile); - var sqliteDatabaseCreator = new SqliteDatabaseCreator(); + var sqliteDatabaseCreator = new SqliteDatabaseCreator(DefaultCollation); sqliteDatabaseCreator.Create(context.Database, model); Seed(context); diff --git a/SQLite.CodeFirst/Public/SqliteDatabaseCreator.cs b/SQLite.CodeFirst/Public/SqliteDatabaseCreator.cs index 4fd325e..0626c24 100644 --- a/SQLite.CodeFirst/Public/SqliteDatabaseCreator.cs +++ b/SQLite.CodeFirst/Public/SqliteDatabaseCreator.cs @@ -16,6 +16,13 @@ namespace SQLite.CodeFirst /// public class SqliteDatabaseCreator : IDatabaseCreator { + public SqliteDatabaseCreator(Collation defaultCollation = null) + { + DefaultCollation = defaultCollation; + } + + public Collation DefaultCollation { get; } + /// /// Creates the SQLite-Database. /// @@ -24,7 +31,7 @@ public void Create(Database db, DbModel model) if (db == null) throw new ArgumentNullException("db"); if (model == null) throw new ArgumentNullException("model"); - var sqliteSqlGenerator = new SqliteSqlGenerator(); + var sqliteSqlGenerator = new SqliteSqlGenerator(DefaultCollation); string sql = sqliteSqlGenerator.Generate(model.StoreModel); Debug.Write(sql); db.ExecuteSqlCommand(TransactionalBehavior.EnsureTransaction, sql); diff --git a/SQLite.CodeFirst/Public/SqliteSqlGenerator.cs b/SQLite.CodeFirst/Public/SqliteSqlGenerator.cs index d0f248a..944115e 100644 --- a/SQLite.CodeFirst/Public/SqliteSqlGenerator.cs +++ b/SQLite.CodeFirst/Public/SqliteSqlGenerator.cs @@ -9,12 +9,19 @@ namespace SQLite.CodeFirst /// public class SqliteSqlGenerator : ISqlGenerator { + public SqliteSqlGenerator(Collation defaultCollation = null) + { + DefaultCollation = defaultCollation; + } + + public Collation DefaultCollation { get; } + /// /// Generates the SQL statement, based on the . /// public string Generate(EdmModel storeModel) { - IStatementBuilder statementBuilder = new CreateDatabaseStatementBuilder(storeModel); + IStatementBuilder statementBuilder = new CreateDatabaseStatementBuilder(storeModel, DefaultCollation); IStatement statement = statementBuilder.BuildStatement(); return statement.CreateStatement(); }