diff --git a/OptixServe.Api/OptixServe.Api.csproj b/OptixServe.Api/OptixServe.Api.csproj index 79d3b79..88bb489 100644 --- a/OptixServe.Api/OptixServe.Api.csproj +++ b/OptixServe.Api/OptixServe.Api.csproj @@ -16,7 +16,7 @@ enable enable true - false + true diff --git a/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextAssemblyAttributes.cs b/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextAssemblyAttributes.cs new file mode 100644 index 0000000..1e19b39 --- /dev/null +++ b/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextAssemblyAttributes.cs @@ -0,0 +1,9 @@ +// +using Microsoft.EntityFrameworkCore.Infrastructure; +using OptixServe.Infrastructure.Data; +using OptixServe.Infrastructure.Data.CompiledModels; + +#pragma warning disable 219, 612, 618 +#nullable disable + +[assembly: DbContextModel(typeof(AppDbContext), typeof(AppDbContextModel))] diff --git a/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextModel.cs b/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextModel.cs new file mode 100644 index 0000000..e39c666 --- /dev/null +++ b/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextModel.cs @@ -0,0 +1,47 @@ +// +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace OptixServe.Infrastructure.Data.CompiledModels +{ + [DbContext(typeof(AppDbContext))] + public partial class AppDbContextModel : RuntimeModel + { + private static readonly bool _useOldBehavior31751 = + System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751; + + static AppDbContextModel() + { + var model = new AppDbContextModel(); + + if (_useOldBehavior31751) + { + model.Initialize(); + } + else + { + var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024); + thread.Start(); + thread.Join(); + + void RunInitialization() + { + model.Initialize(); + } + } + + model.Customize(); + _instance = (AppDbContextModel)model.FinalizeModel(); + } + + private static AppDbContextModel _instance; + public static IModel Instance => _instance; + + partial void Initialize(); + + partial void Customize(); + } +} diff --git a/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextModelBuilder.cs b/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextModelBuilder.cs new file mode 100644 index 0000000..c2b61a7 --- /dev/null +++ b/OptixServe.Infrastructure/Data/CompiledModels/AppDbContextModelBuilder.cs @@ -0,0 +1,99 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Update.Internal; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace OptixServe.Infrastructure.Data.CompiledModels +{ + public partial class AppDbContextModel + { + private AppDbContextModel() + : base(skipDetectChanges: false, modelId: new Guid("3214a553-d69f-4844-a587-080f6d463671"), entityTypeCount: 1) + { + } + + partial void Initialize() + { + var user = UserEntityType.Create(this); + + UserEntityType.CreateAnnotations(user); + + AddAnnotation("ProductVersion", "9.0.6"); + AddRuntimeAnnotation("Relational:RelationalModelFactory", () => CreateRelationalModel()); + } + + private IRelationalModel CreateRelationalModel() + { + var relationalModel = new RelationalModel(this); + + var user = FindEntityType("OptixServe.Core.Models.User")!; + + var defaultTableMappings = new List>(); + user.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings); + var optixServeCoreModelsUserTableBase = new TableBase("OptixServe.Core.Models.User", null, relationalModel); + var idColumnBase = new ColumnBase("Id", "TEXT", optixServeCoreModelsUserTableBase); + optixServeCoreModelsUserTableBase.Columns.Add("Id", idColumnBase); + var passwordColumnBase = new ColumnBase("Password", "TEXT", optixServeCoreModelsUserTableBase) + { + IsNullable = true + }; + optixServeCoreModelsUserTableBase.Columns.Add("Password", passwordColumnBase); + var privilegeGroupColumnBase = new ColumnBase("PrivilegeGroup", "INTEGER", optixServeCoreModelsUserTableBase); + optixServeCoreModelsUserTableBase.Columns.Add("PrivilegeGroup", privilegeGroupColumnBase); + var userNameColumnBase = new ColumnBase("UserName", "TEXT", optixServeCoreModelsUserTableBase); + optixServeCoreModelsUserTableBase.Columns.Add("UserName", userNameColumnBase); + relationalModel.DefaultTables.Add("OptixServe.Core.Models.User", optixServeCoreModelsUserTableBase); + var optixServeCoreModelsUserMappingBase = new TableMappingBase(user, optixServeCoreModelsUserTableBase, null); + optixServeCoreModelsUserTableBase.AddTypeMapping(optixServeCoreModelsUserMappingBase, false); + defaultTableMappings.Add(optixServeCoreModelsUserMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase, user.FindProperty("Id")!, optixServeCoreModelsUserMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)passwordColumnBase, user.FindProperty("Password")!, optixServeCoreModelsUserMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)privilegeGroupColumnBase, user.FindProperty("PrivilegeGroup")!, optixServeCoreModelsUserMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)userNameColumnBase, user.FindProperty("UserName")!, optixServeCoreModelsUserMappingBase); + + var tableMappings = new List(); + user.SetRuntimeAnnotation("Relational:TableMappings", tableMappings); + var usersTable = new Table("Users", null, relationalModel); + var idColumn = new Column("Id", "TEXT", usersTable); + usersTable.Columns.Add("Id", idColumn); + idColumn.Accessors = ColumnAccessorsFactory.CreateGeneric(idColumn); + var passwordColumn = new Column("Password", "TEXT", usersTable) + { + IsNullable = true + }; + usersTable.Columns.Add("Password", passwordColumn); + passwordColumn.Accessors = ColumnAccessorsFactory.CreateGeneric(passwordColumn); + var privilegeGroupColumn = new Column("PrivilegeGroup", "INTEGER", usersTable); + usersTable.Columns.Add("PrivilegeGroup", privilegeGroupColumn); + privilegeGroupColumn.Accessors = ColumnAccessorsFactory.CreateGeneric(privilegeGroupColumn); + var userNameColumn = new Column("UserName", "TEXT", usersTable); + usersTable.Columns.Add("UserName", userNameColumn); + userNameColumn.Accessors = ColumnAccessorsFactory.CreateGeneric(userNameColumn); + relationalModel.Tables.Add(("Users", null), usersTable); + var usersTableMapping = new TableMapping(user, usersTable, null); + usersTable.AddTypeMapping(usersTableMapping, false); + tableMappings.Add(usersTableMapping); + RelationalModel.CreateColumnMapping(idColumn, user.FindProperty("Id")!, usersTableMapping); + RelationalModel.CreateColumnMapping(passwordColumn, user.FindProperty("Password")!, usersTableMapping); + RelationalModel.CreateColumnMapping(privilegeGroupColumn, user.FindProperty("PrivilegeGroup")!, usersTableMapping); + RelationalModel.CreateColumnMapping(userNameColumn, user.FindProperty("UserName")!, usersTableMapping); + var pK_Users = new UniqueConstraint("PK_Users", usersTable, new[] { idColumn }); + usersTable.PrimaryKey = pK_Users; + pK_Users.SetRowKeyValueFactory(new SimpleRowKeyValueFactory(pK_Users)); + var pK_UsersKey = RelationalModel.GetKey(this, + "OptixServe.Core.Models.User", + new[] { "Id" }); + pK_Users.MappedKeys.Add(pK_UsersKey); + RelationalModel.GetOrCreateUniqueConstraints(pK_UsersKey).Add(pK_Users); + usersTable.UniqueConstraints.Add("PK_Users", pK_Users); + return relationalModel.MakeReadOnly(); + } + } +} diff --git a/OptixServe.Infrastructure/Data/CompiledModels/UserEntityType.cs b/OptixServe.Infrastructure/Data/CompiledModels/UserEntityType.cs new file mode 100644 index 0000000..ec6b122 --- /dev/null +++ b/OptixServe.Infrastructure/Data/CompiledModels/UserEntityType.cs @@ -0,0 +1,227 @@ +// +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Json; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using OptixServe.Core.Models; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace OptixServe.Infrastructure.Data.CompiledModels +{ + [EntityFrameworkInternal] + public partial class UserEntityType + { + public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null) + { + var runtimeEntityType = model.AddEntityType( + "OptixServe.Core.Models.User", + typeof(User), + baseEntityType, + propertyCount: 4, + keyCount: 1); + + var id = runtimeEntityType.AddProperty( + "Id", + typeof(string), + propertyInfo: typeof(User).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(User).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + afterSaveBehavior: PropertySaveBehavior.Throw); + id.SetGetter( + string (User entity) => UserUnsafeAccessors.Id(entity), + bool (User entity) => UserUnsafeAccessors.Id(entity) == null, + string (User instance) => UserUnsafeAccessors.Id(instance), + bool (User instance) => UserUnsafeAccessors.Id(instance) == null); + id.SetSetter( + (User entity, string value) => UserUnsafeAccessors.Id(entity) = value); + id.SetMaterializationSetter( + (User entity, string value) => UserUnsafeAccessors.Id(entity) = value); + id.SetAccessors( + string (InternalEntityEntry entry) => UserUnsafeAccessors.Id(((User)(entry.Entity))), + string (InternalEntityEntry entry) => UserUnsafeAccessors.Id(((User)(entry.Entity))), + string (InternalEntityEntry entry) => entry.ReadOriginalValue(id, 0), + string (InternalEntityEntry entry) => entry.ReadRelationshipSnapshotValue(id, 0), + object (ValueBuffer valueBuffer) => valueBuffer[0]); + id.SetPropertyIndexes( + index: 0, + originalValueIndex: 0, + shadowIndex: -1, + relationshipIndex: 0, + storeGenerationIndex: -1); + id.TypeMapping = SqliteStringTypeMapping.Default; + id.SetCurrentValueComparer(new EntryCurrentValueComparer(id)); + + var password = runtimeEntityType.AddProperty( + "Password", + typeof(string), + propertyInfo: typeof(User).GetProperty("Password", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(User).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + nullable: true); + password.SetGetter( + string (User entity) => UserUnsafeAccessors.Password(entity), + bool (User entity) => UserUnsafeAccessors.Password(entity) == null, + string (User instance) => UserUnsafeAccessors.Password(instance), + bool (User instance) => UserUnsafeAccessors.Password(instance) == null); + password.SetSetter( + (User entity, string value) => UserUnsafeAccessors.Password(entity) = value); + password.SetMaterializationSetter( + (User entity, string value) => UserUnsafeAccessors.Password(entity) = value); + password.SetAccessors( + string (InternalEntityEntry entry) => UserUnsafeAccessors.Password(((User)(entry.Entity))), + string (InternalEntityEntry entry) => UserUnsafeAccessors.Password(((User)(entry.Entity))), + string (InternalEntityEntry entry) => entry.ReadOriginalValue(password, 1), + string (InternalEntityEntry entry) => entry.GetCurrentValue(password), + object (ValueBuffer valueBuffer) => valueBuffer[1]); + password.SetPropertyIndexes( + index: 1, + originalValueIndex: 1, + shadowIndex: -1, + relationshipIndex: -1, + storeGenerationIndex: -1); + password.TypeMapping = SqliteStringTypeMapping.Default; + + var privilegeGroup = runtimeEntityType.AddProperty( + "PrivilegeGroup", + typeof(PrivilegeGroup), + propertyInfo: typeof(User).GetProperty("PrivilegeGroup", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(User).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)); + privilegeGroup.SetGetter( + PrivilegeGroup (User entity) => UserUnsafeAccessors.PrivilegeGroup(entity), + bool (User entity) => object.Equals(((object)(UserUnsafeAccessors.PrivilegeGroup(entity))), ((object)(PrivilegeGroup.Admin))), + PrivilegeGroup (User instance) => UserUnsafeAccessors.PrivilegeGroup(instance), + bool (User instance) => object.Equals(((object)(UserUnsafeAccessors.PrivilegeGroup(instance))), ((object)(PrivilegeGroup.Admin)))); + privilegeGroup.SetSetter( + (User entity, PrivilegeGroup value) => UserUnsafeAccessors.PrivilegeGroup(entity) = value); + privilegeGroup.SetMaterializationSetter( + (User entity, PrivilegeGroup value) => UserUnsafeAccessors.PrivilegeGroup(entity) = value); + privilegeGroup.SetAccessors( + PrivilegeGroup (InternalEntityEntry entry) => UserUnsafeAccessors.PrivilegeGroup(((User)(entry.Entity))), + PrivilegeGroup (InternalEntityEntry entry) => UserUnsafeAccessors.PrivilegeGroup(((User)(entry.Entity))), + PrivilegeGroup (InternalEntityEntry entry) => entry.ReadOriginalValue(privilegeGroup, 2), + PrivilegeGroup (InternalEntityEntry entry) => entry.GetCurrentValue(privilegeGroup), + object (ValueBuffer valueBuffer) => valueBuffer[2]); + privilegeGroup.SetPropertyIndexes( + index: 2, + originalValueIndex: 2, + shadowIndex: -1, + relationshipIndex: -1, + storeGenerationIndex: -1); + privilegeGroup.TypeMapping = IntTypeMapping.Default.Clone( + comparer: new ValueComparer( + bool (PrivilegeGroup v1, PrivilegeGroup v2) => object.Equals(((object)(v1)), ((object)(v2))), + int (PrivilegeGroup v) => ((object)v).GetHashCode(), + PrivilegeGroup (PrivilegeGroup v) => v), + keyComparer: new ValueComparer( + bool (PrivilegeGroup v1, PrivilegeGroup v2) => object.Equals(((object)(v1)), ((object)(v2))), + int (PrivilegeGroup v) => ((object)v).GetHashCode(), + PrivilegeGroup (PrivilegeGroup v) => v), + providerValueComparer: new ValueComparer( + bool (int v1, int v2) => v1 == v2, + int (int v) => v, + int (int v) => v), + mappingInfo: new RelationalTypeMappingInfo( + storeTypeName: "INTEGER"), + converter: new ValueConverter( + int (PrivilegeGroup value) => ((int)(value)), + PrivilegeGroup (int value) => ((PrivilegeGroup)(value))), + jsonValueReaderWriter: new JsonConvertedValueReaderWriter( + JsonInt32ReaderWriter.Instance, + new ValueConverter( + int (PrivilegeGroup value) => ((int)(value)), + PrivilegeGroup (int value) => ((PrivilegeGroup)(value))))); + privilegeGroup.SetSentinelFromProviderValue(0); + + var userName = runtimeEntityType.AddProperty( + "UserName", + typeof(string), + propertyInfo: typeof(User).GetProperty("UserName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(User).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)); + userName.SetGetter( + string (User entity) => UserUnsafeAccessors.UserName(entity), + bool (User entity) => UserUnsafeAccessors.UserName(entity) == null, + string (User instance) => UserUnsafeAccessors.UserName(instance), + bool (User instance) => UserUnsafeAccessors.UserName(instance) == null); + userName.SetSetter( + (User entity, string value) => UserUnsafeAccessors.UserName(entity) = value); + userName.SetMaterializationSetter( + (User entity, string value) => UserUnsafeAccessors.UserName(entity) = value); + userName.SetAccessors( + string (InternalEntityEntry entry) => UserUnsafeAccessors.UserName(((User)(entry.Entity))), + string (InternalEntityEntry entry) => UserUnsafeAccessors.UserName(((User)(entry.Entity))), + string (InternalEntityEntry entry) => entry.ReadOriginalValue(userName, 3), + string (InternalEntityEntry entry) => entry.GetCurrentValue(userName), + object (ValueBuffer valueBuffer) => valueBuffer[3]); + userName.SetPropertyIndexes( + index: 3, + originalValueIndex: 3, + shadowIndex: -1, + relationshipIndex: -1, + storeGenerationIndex: -1); + userName.TypeMapping = SqliteStringTypeMapping.Default; + + var key = runtimeEntityType.AddKey( + new[] { id }); + runtimeEntityType.SetPrimaryKey(key); + + return runtimeEntityType; + } + + public static void CreateAnnotations(RuntimeEntityType runtimeEntityType) + { + var id = runtimeEntityType.FindProperty("Id"); + var password = runtimeEntityType.FindProperty("Password"); + var privilegeGroup = runtimeEntityType.FindProperty("PrivilegeGroup"); + var userName = runtimeEntityType.FindProperty("UserName"); + var key = runtimeEntityType.FindKey(new[] { id }); + key.SetPrincipalKeyValueFactory(KeyValueFactoryFactory.CreateSimpleNullableFactory(key)); + key.SetIdentityMapFactory(IdentityMapFactoryFactory.CreateFactory(key)); + runtimeEntityType.SetOriginalValuesFactory( + ISnapshot (InternalEntityEntry source) => + { + var entity = ((User)(source.Entity)); + return ((ISnapshot)(new Snapshot((source.GetCurrentValue(id) == null ? null : ((ValueComparer)(((IProperty)id).GetValueComparer())).Snapshot(source.GetCurrentValue(id))), (source.GetCurrentValue(password) == null ? null : ((ValueComparer)(((IProperty)password).GetValueComparer())).Snapshot(source.GetCurrentValue(password))), ((ValueComparer)(((IProperty)privilegeGroup).GetValueComparer())).Snapshot(source.GetCurrentValue(privilegeGroup)), (source.GetCurrentValue(userName) == null ? null : ((ValueComparer)(((IProperty)userName).GetValueComparer())).Snapshot(source.GetCurrentValue(userName)))))); + }); + runtimeEntityType.SetStoreGeneratedValuesFactory( + ISnapshot () => Snapshot.Empty); + runtimeEntityType.SetTemporaryValuesFactory( + ISnapshot (InternalEntityEntry source) => Snapshot.Empty); + runtimeEntityType.SetShadowValuesFactory( + ISnapshot (IDictionary source) => Snapshot.Empty); + runtimeEntityType.SetEmptyShadowValuesFactory( + ISnapshot () => Snapshot.Empty); + runtimeEntityType.SetRelationshipSnapshotFactory( + ISnapshot (InternalEntityEntry source) => + { + var entity = ((User)(source.Entity)); + return ((ISnapshot)(new Snapshot((source.GetCurrentValue(id) == null ? null : ((ValueComparer)(((IProperty)id).GetKeyValueComparer())).Snapshot(source.GetCurrentValue(id)))))); + }); + runtimeEntityType.Counts = new PropertyCounts( + propertyCount: 4, + navigationCount: 0, + complexPropertyCount: 0, + originalValueCount: 4, + shadowCount: 0, + relationshipCount: 1, + storeGeneratedCount: 0); + runtimeEntityType.AddAnnotation("Relational:FunctionName", null); + runtimeEntityType.AddAnnotation("Relational:Schema", null); + runtimeEntityType.AddAnnotation("Relational:SqlQuery", null); + runtimeEntityType.AddAnnotation("Relational:TableName", "Users"); + runtimeEntityType.AddAnnotation("Relational:ViewName", null); + runtimeEntityType.AddAnnotation("Relational:ViewSchema", null); + + Customize(runtimeEntityType); + } + + static partial void Customize(RuntimeEntityType runtimeEntityType); + } +} diff --git a/OptixServe.Infrastructure/Data/CompiledModels/UserUnsafeAccessors.cs b/OptixServe.Infrastructure/Data/CompiledModels/UserUnsafeAccessors.cs new file mode 100644 index 0000000..7ce25c7 --- /dev/null +++ b/OptixServe.Infrastructure/Data/CompiledModels/UserUnsafeAccessors.cs @@ -0,0 +1,25 @@ +// +using System; +using System.Runtime.CompilerServices; +using OptixServe.Core.Models; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace OptixServe.Infrastructure.Data.CompiledModels +{ + public static class UserUnsafeAccessors + { + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "k__BackingField")] + public static extern ref string Id(User @this); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "k__BackingField")] + public static extern ref string Password(User @this); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "k__BackingField")] + public static extern ref PrivilegeGroup PrivilegeGroup(User @this); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "k__BackingField")] + public static extern ref string UserName(User @this); + } +} diff --git a/OptixServe.Infrastructure/EFCore-NativeAOT-Intergration.md b/OptixServe.Infrastructure/EFCore-NativeAOT-Intergration.md new file mode 100644 index 0000000..43eb346 --- /dev/null +++ b/OptixServe.Infrastructure/EFCore-NativeAOT-Intergration.md @@ -0,0 +1,82 @@ +# EFCore Intergration + +## Introduction + +This app relies on EF Core to access the database. + +However, it is NOT so smooth when work with NativeAOT. + +To use EF Core, see below. + +## DesignTimeDbContextFactory + +To work with NativeAOT, a code-defined way to create DbContext instance is a MUST in nearly ALL operations of EF Core, letting ef tool discover the DbContext. + +In this project, `OptixServe.Infrastructure/Utilites/DesignTimeDbContextFactory.cs` is set up to do this. + +This class implements a simple commandline arguments parser, enabling passing arguments along with `dotnet ef`. + +Currently, there are two options, `--config/-c` and `--data-dir/-d` are supported. See documents there. + +To pass arguments/options to `CreateDbContext` static method, pass the arguments following with `dotnet ef` command, with two dashes splitting. + +For example: + +```bash +dotnet ef database update -- -c ../data/appsettings.Development.json -d ../data/ +``` + +## Workflow + +To make the code work, following the steps: + +1. Implement other parts +2. Compile the data models, with `--nativeaot` option. +3. Add migration +4. Update database +5. Build project, and Run! + +Here are the details. + +### Requirements + +See [https://learn.microsoft.com/en-us/ef/core/performance/nativeaot-and-precompiled-queries]() + +### Compile Models + +```bash +dotnet ef dbcontext optimize --output-dir Data/CompiledModels --precompile-queries --nativeaot -- -c ../data_dev/appsettings.Development.json -d ../data_dev/ +``` + +If this is the first time to run `dbcontext optimize`, DO NOT forget to `UseModel` in DbContext construction. + +```cs OptixServe.Infrastructure/Utilites/DatabaseHelper.cs +public static void ConfigureDbContext(DbContextOptionsBuilder options) +{ + // ... + options.UseSqlite(connectionString, b => b.MigrationsAssembly("OptixServe.Infrastructure")) + .UseModel(AppDbContextModel.Instance); + // ... +} +``` + + +### Add Migration + +```bash +dotnet ef migrations add InitialCreate -- -c ../data_dev/appsettings.Development.json +``` + + +### Update Database + +```bash +dotnet ef database update -- -c ../data_dev/appsettings.Development.json -d ../data_dev/ +``` + + +### Build Project + +```bash +dotnet publish -c Release -r linux-x64 +``` \ No newline at end of file diff --git a/OptixServe.Infrastructure/OptixServe.Infrastructure.csproj b/OptixServe.Infrastructure/OptixServe.Infrastructure.csproj index 4f4b623..3e0efe0 100644 --- a/OptixServe.Infrastructure/OptixServe.Infrastructure.csproj +++ b/OptixServe.Infrastructure/OptixServe.Infrastructure.csproj @@ -9,6 +9,10 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -20,6 +24,7 @@ net9.0 enable enable + $(InterceptorsNamespaces);Microsoft.EntityFrameworkCore.GeneratedInterceptors diff --git a/OptixServe.Infrastructure/Utilites/DatabaseHelper.cs b/OptixServe.Infrastructure/Utilites/DatabaseHelper.cs index 580e5fc..a546cba 100644 --- a/OptixServe.Infrastructure/Utilites/DatabaseHelper.cs +++ b/OptixServe.Infrastructure/Utilites/DatabaseHelper.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using OptixServe.Infrastructure.Configuration; +using OptixServe.Infrastructure.Data.CompiledModels; namespace OptixServe.Infrastructure.Utilites; @@ -22,7 +23,8 @@ public static class DatabaseHelper var dbPath = dbSettings.Host ?? "optixserve.db"; var connectionString = $"Data Source={dbPath}"; - options.UseSqlite(connectionString, b => b.MigrationsAssembly("OptixServe.Infrastructure")); + options.UseSqlite(connectionString, b => b.MigrationsAssembly("OptixServe.Infrastructure")) + .UseModel(AppDbContextModel.Instance); } else