├── EntityFrameworkCore.BootKit
├── Models
│ ├── DbExecutionOptions.cs
│ ├── DatabaseType.cs
│ ├── DbRecord.cs
│ ├── DbPatchModel.cs
│ └── DatabaseBind.cs
├── DatabaseExtensions
│ ├── HasNoKeyAttribute.cs
│ ├── FactoryDatabaseExtension.cs
│ └── TransactionDatabaseExtension.cs
├── Interfaces
│ ├── IDbRecord.cs
│ └── IRequireDbPermission.cs
├── DbConnectionSetting.cs
├── DatabaseSettings.cs
├── DbContexts
│ ├── DbContext4Memory.cs
│ ├── MongoDbConnection.cs
│ ├── DataContext.cs
│ └── DbContext4SqlServer.cs
├── DefaultDataContextLoader.cs
├── EntityFrameworkCore.BootKit.csproj
├── Utility.cs
└── Database.cs
├── Directory.Build.props
├── EntityFrameworkCore.BootKit.UnitTest
├── Tables
│ ├── PizzaType.cs
│ ├── MongoDbCollection.cs
│ └── PIzzaOrder.cs
├── EntityFrameworkCore.BootKit.UnitTest.csproj
└── DatabaseTest.cs
├── docs
├── index.rst
├── Makefile
├── make.bat
└── conf.py
├── EntityFrameworkCore.BootKit.Postgre
├── DbContext4Redshift.cs
├── DbContext4PostgreSql.cs
├── EntityFrameworkCore.BootKit.Postgre.csproj
└── PostgreContextOptionsExtensions.cs
├── EntityFrameworkCore.BootKit.Mongo
├── EntityFrameworkCore.BootKit.Mongo.csproj
├── MongoDbContextOptionsExtensions.cs
├── DbContext4MongoDb.cs
└── MongoDbQueryExtension.cs
├── LICENSE
├── EntityFrameworkCore.BootKit.MySql
├── MySqlContextOptionsExtensions.cs
├── EntityFrameworkCore.BootKit.MySql.csproj
├── DbContext4Aurora.cs
└── DbContext4MySql.cs
├── EntityFrameworkCore.BootKit.Sqlite
├── EntityFrameworkCore.BootKit.Sqlite.csproj
└── DbContext4Sqlite.cs
├── EntityFrameworkCore.BootKit.sln
├── README.md
└── .gitignore
/EntityFrameworkCore.BootKit/Models/DbExecutionOptions.cs:
--------------------------------------------------------------------------------
1 | namespace EntityFrameworkCore.BootKit.Models;
2 |
3 | public class DbExecutionOptions
4 | {
5 | public int Timeout { get; set; } = 30;
6 | }
7 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DatabaseExtensions/HasNoKeyAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace EntityFrameworkCore.BootKit
6 | {
7 | public class HasNoKeyAttribute : Attribute
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Interfaces/IDbRecord.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace EntityFrameworkCore.BootKit
6 | {
7 | ///
8 | /// EF BootKit will generate a concrete table in corresponding database
9 | ///
10 | public interface IDbRecord
11 | {
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Models/DatabaseType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace EntityFrameworkCore.BootKit
6 | {
7 | public enum DatabaseType
8 | {
9 | InMemory = 1,
10 | Sqlite = 2,
11 | SqlServer = 3,
12 | MySql = 4,
13 | Oracle = 5,
14 | MongoDb = 6,
15 | PostgreSql = 7,
16 | Redshift = 8
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DbConnectionSetting.cs:
--------------------------------------------------------------------------------
1 | namespace EntityFrameworkCore.BootKit;
2 |
3 | public class DbConnectionSetting
4 | {
5 | public DbConnectionSetting()
6 | {
7 | Slavers = [];
8 | }
9 |
10 | public string Master { get; set; }
11 | public string[] Slavers { get; set; }
12 |
13 | public int ConnectionTimeout { get; set; } = 30;
14 |
15 | public int ExecutionTimeout { get; set; } = 30;
16 | }
17 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DatabaseSettings.cs:
--------------------------------------------------------------------------------
1 | namespace EntityFrameworkCore.BootKit;
2 |
3 | public class DatabaseSettings
4 | {
5 | public string Default { get; set; }
6 | public DbConnectionSetting DefaultConnection { get; set; }
7 | public bool EnableSqlLog { get; set; }
8 | public bool EnableSensitiveDataLogging { get; set; }
9 | public bool EnableRetryOnFailure { get; set; }
10 | public bool UseCamelCase { get; set; }
11 | }
12 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Models/DbRecord.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Text;
6 |
7 | namespace EntityFrameworkCore.BootKit
8 | {
9 | public abstract class DbRecord
10 | {
11 | [Key]
12 | [StringLength(36)]
13 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
14 | public string Id { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 14.0
4 | 10.0.0
5 | 5.0.17
6 | 6.0.36
7 | 8.0.13
8 | 10.0.0
9 | true
10 | false
11 |
12 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.UnitTest/Tables/PizzaType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Text;
5 |
6 | namespace EntityFrameworkCore.BootKit.UnitTest.Tables
7 | {
8 | public class PizzaType : DbRecord, IDbRecord
9 | {
10 | [Required]
11 | public String OrderId { get; set; }
12 |
13 | [Required]
14 | [MaxLength(64)]
15 | public String Name { get; set; }
16 |
17 | public Decimal Amount { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.UnitTest/Tables/MongoDbCollection.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Bson.Serialization.Attributes;
2 | using MongoDB.Bson.Serialization.IdGenerators;
3 |
4 | namespace EntityFrameworkCore.BootKit.UnitTest.Tables
5 | {
6 | [BsonIgnoreExtraElements]
7 | public class MongoDbCollection : INoSqlDbRecord
8 | {
9 | [BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
10 | public string Id { get; set; }
11 |
12 | public string Name { get; set; }
13 | }
14 |
15 | public interface INoSqlDbRecord
16 | {
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. EntityFrameworkCore.BootKit documentation master file, created by
2 | sphinx-quickstart on Tue Aug 21 16:39:58 2018.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to EntityFrameworkCore.BootKit's documentation!
7 | =======================================================
8 |
9 | .. include:: ../README.rst
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 | :caption: Contents:
14 |
15 |
16 |
17 | Indices and tables
18 | ==================
19 |
20 | * :ref:`genindex`
21 | * :ref:`modindex`
22 | * :ref:`search`
23 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Interfaces/IRequireDbPermission.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace EntityFrameworkCore.BootKit
6 | {
7 | ///
8 | /// Get permission before update record, it won't commit when any implementation return false.
9 | ///
10 | public interface IRequireDbPermission
11 | {
12 | ///
13 | /// Allow invoke patch method
14 | ///
15 | ///
16 | ///
17 | Boolean AllowPatch(DbPatchModel patch);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = EntityFrameworkCoreBootKit
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.UnitTest/Tables/PIzzaOrder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Text;
6 |
7 | namespace EntityFrameworkCore.BootKit.UnitTest.Tables
8 | {
9 | public class PizzaOrder : DbRecord, IDbRecord
10 | {
11 | [MaxLength(32)]
12 | public String OrderNumber { get; set; }
13 |
14 | [MaxLength(64)]
15 | public String CustomerName { get; set; }
16 |
17 | [Required]
18 | public DateTime CreatedTime { get; set; }
19 |
20 | [ForeignKey("OrderId")]
21 | public List PizzaTypes { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Models/DbPatchModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace EntityFrameworkCore.BootKit
6 | {
7 | public class DbPatchModel
8 | {
9 | public DbPatchModel()
10 | {
11 | Values = new Dictionary { };
12 | IgnoredColumns = new List();
13 | }
14 |
15 | public string Id { get; set; }
16 | public string Table { get; set; }
17 | public string Where { get; set; }
18 | public object[] Params { get; set; }
19 |
20 | public List IgnoredColumns { get; set; }
21 |
22 | public Dictionary Values { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Postgre/DbContext4Redshift.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace EntityFrameworkCore.BootKit.DbContexts;
4 |
5 | public class DbContext4Redshift : DataContext
6 | {
7 | public DbContext4Redshift(DbContextOptions options, IServiceProvider serviceProvider)
8 | : base(options, serviceProvider) { }
9 |
10 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
11 | {
12 | SetLog(optionsBuilder);
13 | optionsBuilder.UseNpgsql(ConnectionString,
14 | x =>
15 | {
16 | x.UseNetTopologySuite();
17 | if (enableRetryOnFailure)
18 | {
19 | x.EnableRetryOnFailure();
20 | }
21 | });
22 | base.OnConfiguring(optionsBuilder);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DbContexts/DbContext4Memory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace EntityFrameworkCore.BootKit
7 | {
8 | ///
9 | /// https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/in-memory
10 | ///
11 | public class DbContext4Memory : DataContext
12 | {
13 | public DbContext4Memory(DbContextOptions options, IServiceProvider serviceProvider)
14 | : base(options, serviceProvider) { }
15 |
16 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
17 | {
18 | SetLog(optionsBuilder);
19 | optionsBuilder.UseInMemoryDatabase(ConnectionString);
20 | base.OnConfiguring(optionsBuilder);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 | set SPHINXPROJ=EntityFrameworkCoreBootKit
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
20 | echo.installed, then set the SPHINXBUILD environment variable to point
21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
22 | echo.may add the Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Mongo/EntityFrameworkCore.BootKit.Mongo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net10.0;net8.0;net6.0;netstandard2.1
5 | $(GeneratePackageOnBuild)
6 | enable
7 | enable
8 | $(BootKitVersion)
9 | $(BootKitVersion)
10 | $(BootKitVersion)
11 | https://avatars3.githubusercontent.com/u/44989469?s=200&v=4
12 | MIT
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Models/DatabaseBind.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.Common;
4 | using System.Text;
5 |
6 | namespace EntityFrameworkCore.BootKit
7 | {
8 | public class DatabaseBind
9 | {
10 | public DbConnection MasterConnection { get; set; }
11 | public DataContext DbContextMaster { get; set; }
12 |
13 | public int SlaveId { get; set; }
14 | public bool IsRelational { get; set; } = true;
15 | public List SlaveConnections { get; set; }
16 | public DbConnection SlaveConnection => SlaveConnections[SlaveId];
17 | public DataContext DbContextSlaver { get; set; }
18 |
19 | public Type TableInterface { get; set; }
20 |
21 | public Type DbContextType { get; set; }
22 |
23 | public List Entities { get; set; }
24 |
25 | public Boolean CreateDbIfNotExist { get; set; }
26 | public IServiceProvider ServiceProvider { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Haiping Chen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.UnitTest/EntityFrameworkCore.BootKit.UnitTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net10.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Mongo/MongoDbContextOptionsExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using MongoDB.Driver;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 |
5 | namespace EntityFrameworkCore.BootKit;
6 |
7 | public static class MongoDbContextOptionsExtensions
8 | {
9 | public static DbContextOptionsBuilder UseMongoDb(this DbContextOptionsBuilder optionsBuilder, string connectionString)
10 | {
11 | return optionsBuilder;
12 | }
13 |
14 | public static IMongoCollection Collection(this Database database, string name = "") where T : class
15 | {
16 | Type entityType = typeof(T);
17 |
18 | DatabaseBind binding = database.DbContextBinds.First(x => x.GetType().Equals(typeof(DatabaseBind)));
19 | var db = database.GetMaster(entityType);
20 | if (string.IsNullOrEmpty(name))
21 | {
22 | // Default collection name
23 | name = typeof(T).Name;
24 |
25 | // Check if the class has TableAttribute
26 | var attributes = typeof(T).GetCustomAttributesData()
27 | .FirstOrDefault(x => x.AttributeType == typeof(TableAttribute));
28 | if (attributes != null)
29 | {
30 | var arguments = attributes.ConstructorArguments;
31 | if (arguments.Count > 0)
32 | {
33 | name = attributes.ConstructorArguments[0].Value.ToString();
34 | }
35 | }
36 | }
37 | return (db as DbContext4MongoDb).Set(name);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DbContexts/MongoDbConnection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Data.Common;
5 | using System.Text;
6 |
7 | namespace EntityFrameworkCore.BootKit
8 | {
9 | public sealed class MongoDbConnection : DbConnection, ICloneable
10 | {
11 | public override string ConnectionString { get; set; }
12 |
13 | public override string Database => throw new NotImplementedException();
14 |
15 | public override string DataSource => throw new NotImplementedException();
16 |
17 | public override string ServerVersion => throw new NotImplementedException();
18 |
19 | public override ConnectionState State => throw new NotImplementedException();
20 |
21 | public MongoDbConnection()
22 | {
23 |
24 | }
25 |
26 | public MongoDbConnection(string connectionString)
27 | {
28 | ConnectionString = connectionString;
29 | }
30 |
31 | public object Clone()
32 | {
33 | throw new NotImplementedException();
34 | }
35 |
36 | protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
37 | {
38 | throw new NotImplementedException();
39 | }
40 |
41 | public override void ChangeDatabase(string databaseName)
42 | {
43 | throw new NotImplementedException();
44 | }
45 |
46 | public override void Close()
47 | {
48 | throw new NotImplementedException();
49 | }
50 |
51 | protected override DbCommand CreateDbCommand()
52 | {
53 | throw new NotImplementedException();
54 | }
55 |
56 | public override void Open()
57 | {
58 | throw new NotImplementedException();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.MySql/MySqlContextOptionsExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using MySqlConnector;
3 |
4 | namespace EntityFrameworkCore.BootKit;
5 |
6 | public static class MySqlContextOptionsExtensions
7 | {
8 | public static Database GetDefaultPostgre(this DefaultDataContextLoader loader, string dbConfigSection)
9 | {
10 | var dc = new Database();
11 |
12 | var config = (IConfiguration)AppDomain.CurrentDomain.GetData("Configuration");
13 | var contentRootPath = AppDomain.CurrentDomain.GetData("ContentRootPath").ToString();
14 |
15 | string db = config.GetSection($"{dbConfigSection}:Default").Value;
16 | string connectionString = config.GetSection($"{dbConfigSection}:ConnectionStrings")[db];
17 |
18 | if (db.Equals("MySql"))
19 | {
20 | dc.BindDbContext(new DatabaseBind
21 | {
22 | MasterConnection = new MySqlConnection(connectionString),
23 | CreateDbIfNotExist = true
24 | });
25 | }
26 |
27 | return dc;
28 | }
29 |
30 | public static Database GetDefaultRedshift(this DefaultDataContextLoader loader, string dbConfigSection)
31 | {
32 | var dc = new Database();
33 |
34 | var config = (IConfiguration)AppDomain.CurrentDomain.GetData("Configuration");
35 | var contentRootPath = AppDomain.CurrentDomain.GetData("ContentRootPath").ToString();
36 |
37 | string db = config.GetSection($"{dbConfigSection}:Default").Value;
38 | string connectionString = config.GetSection($"{dbConfigSection}:ConnectionStrings")[db];
39 |
40 | if (db.Equals("Aurora"))
41 | {
42 | dc.BindDbContext(new DatabaseBind
43 | {
44 | MasterConnection = new MySqlConnection(connectionString),
45 | CreateDbIfNotExist = true
46 | });
47 | }
48 |
49 | return dc;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.MySql/EntityFrameworkCore.BootKit.MySql.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net10.0;net8.0;net6.0;netstandard2.1
5 | $(GeneratePackageOnBuild)
6 | enable
7 | enable
8 | $(BootKitVersion)
9 | $(BootKitVersion)
10 | $(BootKitVersion)
11 | https://avatars3.githubusercontent.com/u/44989469?s=200&v=4
12 | MIT
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Postgre/DbContext4PostgreSql.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace EntityFrameworkCore.BootKit.DbContexts;
4 |
5 | public class DbContext4PostgreSql : DataContext
6 | {
7 | public DbContext4PostgreSql(DbContextOptions options, IServiceProvider serviceProvider)
8 | : base(options, serviceProvider) { }
9 |
10 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
11 | {
12 | SetLog(optionsBuilder);
13 | optionsBuilder.UseNpgsql(ConnectionString,
14 | x =>
15 | {
16 | x.UseNetTopologySuite();
17 | if (enableRetryOnFailure)
18 | {
19 | x.EnableRetryOnFailure();
20 | }
21 | });
22 | base.OnConfiguring(optionsBuilder);
23 | }
24 | }
25 |
26 | public class DbContext4PostgreSql2 : DataContext
27 | {
28 | public DbContext4PostgreSql2(DbContextOptions options, IServiceProvider serviceProvider)
29 | : base(options, serviceProvider) { }
30 |
31 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
32 | {
33 | SetLog(optionsBuilder);
34 | optionsBuilder.UseNpgsql(ConnectionString,
35 | x =>
36 | {
37 | x.UseNetTopologySuite();
38 | if (enableRetryOnFailure)
39 | {
40 | x.EnableRetryOnFailure();
41 | }
42 | });
43 | base.OnConfiguring(optionsBuilder);
44 | }
45 | }
46 |
47 | public class DbContext4PostgreSql3 : DataContext
48 | {
49 | public DbContext4PostgreSql3(DbContextOptions options, IServiceProvider serviceProvider)
50 | : base(options, serviceProvider) { }
51 |
52 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
53 | {
54 | SetLog(optionsBuilder);
55 | optionsBuilder.UseNpgsql(ConnectionString,
56 | x =>
57 | {
58 | x.UseNetTopologySuite();
59 | if (enableRetryOnFailure)
60 | {
61 | x.EnableRetryOnFailure();
62 | }
63 | });
64 | base.OnConfiguring(optionsBuilder);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Postgre/EntityFrameworkCore.BootKit.Postgre.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net10.0;net8.0;net6.0;netstandard2.1
5 | $(GeneratePackageOnBuild)
6 | enable
7 | enable
8 | $(BootKitVersion)
9 | $(BootKitVersion)
10 | $(BootKitVersion)
11 | https://avatars3.githubusercontent.com/u/44989469?s=200&v=4
12 | MIT
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.MySql/DbContext4Aurora.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace EntityFrameworkCore.BootKit;
4 |
5 | public class DbContext4Aurora : DataContext
6 | {
7 | public DbContext4Aurora(DbContextOptions options, IServiceProvider serviceProvider)
8 | : base(options, serviceProvider) { }
9 |
10 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
11 | {
12 | SetLog(optionsBuilder);
13 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
14 | x =>
15 | {
16 | x.UseNetTopologySuite();
17 | if (enableRetryOnFailure)
18 | {
19 | x.EnableRetryOnFailure();
20 | }
21 | });
22 | base.OnConfiguring(optionsBuilder);
23 | }
24 | }
25 |
26 | public class DbContext4Aurora2 : DataContext
27 | {
28 | public DbContext4Aurora2(DbContextOptions options, IServiceProvider serviceProvider)
29 | : base(options, serviceProvider) { }
30 |
31 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
32 | {
33 | SetLog(optionsBuilder);
34 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
35 | x =>
36 | {
37 | x.UseNetTopologySuite();
38 | if (enableRetryOnFailure)
39 | {
40 | x.EnableRetryOnFailure();
41 | }
42 | });
43 | base.OnConfiguring(optionsBuilder);
44 | }
45 | }
46 |
47 | public class DbContext4Aurora3 : DataContext
48 | {
49 | public DbContext4Aurora3(DbContextOptions options, IServiceProvider serviceProvider)
50 | : base(options, serviceProvider) { }
51 |
52 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
53 | {
54 | SetLog(optionsBuilder);
55 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
56 | x =>
57 | {
58 | x.UseNetTopologySuite();
59 | if (enableRetryOnFailure)
60 | {
61 | x.EnableRetryOnFailure();
62 | }
63 | });
64 | base.OnConfiguring(optionsBuilder);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Postgre/PostgreContextOptionsExtensions.cs:
--------------------------------------------------------------------------------
1 | using EntityFrameworkCore.BootKit.DbContexts;
2 | using Microsoft.Extensions.Configuration;
3 | using Npgsql;
4 |
5 | namespace EntityFrameworkCore.BootKit;
6 |
7 | public static class PostgreContextOptionsExtensions
8 | {
9 | public static Database GetDefaultPostgre(this DefaultDataContextLoader loader, string dbConfigSection)
10 | {
11 | var dc = new Database();
12 |
13 | var config = (IConfiguration)AppDomain.CurrentDomain.GetData("Configuration");
14 | var contentRootPath = AppDomain.CurrentDomain.GetData("ContentRootPath").ToString();
15 |
16 | string db = config.GetSection($"{dbConfigSection}:Default").Value;
17 | string connectionString = config.GetSection($"{dbConfigSection}:ConnectionStrings")[db];
18 |
19 | if (db.Equals("Redshift"))
20 | {
21 | dc.BindDbContext(new DatabaseBind
22 | {
23 | MasterConnection = new NpgsqlConnection("Server=*.us-east-1.redshift.amazonaws.com; Port=5439;User ID=;Password=;Database=;Server Compatibility Mode=Redshift;SSL Mode=Require;Trust Server Certificate=True;Use SSL Stream=True"),
24 | CreateDbIfNotExist = true
25 | });
26 | }
27 |
28 | return dc;
29 | }
30 |
31 | public static Database GetDefaultRedshift(this DefaultDataContextLoader loader, string dbConfigSection)
32 | {
33 | var dc = new Database();
34 |
35 | var config = (IConfiguration)AppDomain.CurrentDomain.GetData("Configuration");
36 | var contentRootPath = AppDomain.CurrentDomain.GetData("ContentRootPath").ToString();
37 |
38 | string db = config.GetSection($"{dbConfigSection}:Default").Value;
39 | string connectionString = config.GetSection($"{dbConfigSection}:ConnectionStrings")[db];
40 |
41 | if (db.Equals("Redshift"))
42 | {
43 | dc.BindDbContext(new DatabaseBind
44 | {
45 | MasterConnection = new NpgsqlConnection("Server=*.us-east-1.redshift.amazonaws.com; Port=5439;User ID=;Password=;Database=;Server Compatibility Mode=Redshift;SSL Mode=Require;Trust Server Certificate=True;Use SSL Stream=True"),
46 | CreateDbIfNotExist = true
47 | });
48 | }
49 |
50 | return dc;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Sqlite/EntityFrameworkCore.BootKit.Sqlite.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(LangVersion)
5 | net10.0;net8.0;net6.0;netstandard2.1
6 | $(GeneratePackageOnBuild)
7 | enable
8 | enable
9 |
10 | EntityFrameworkCore Boot Kit (EFBK) is a quick start database connecter for using EntityFrameworkCore.
11 | Support variety of databases such as Sqlite, MySql, SqlServer, PostgreSql, MongoDb, Amazon Redshift, AWS Aurora and Memory database.
12 |
13 | https://github.com/Oceania2018/EntityFrameworkCore.BootKit
14 | https://github.com/Oceania2018/EntityFrameworkCore.BootKit
15 | EntityFramework, EntityFrameworkCore, Database, Redshift, Aurora, Postgre, MySql, MongoDB
16 | Haiping Chen
17 | SciSharp STACK
18 | $(BootKitVersion)
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Sqlite/DbContext4Sqlite.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace EntityFrameworkCore.BootKit.Sqlite;
4 |
5 | public class DbContext4Sqlite : DataContext
6 | {
7 | public DbContext4Sqlite(DbContextOptions options, IServiceProvider serviceProvider)
8 | : base(options, serviceProvider) { }
9 |
10 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
11 | {
12 | SetLog(optionsBuilder);
13 | optionsBuilder.UseSqlite(ConnectionString,
14 | x => x.UseNetTopologySuite());
15 | base.OnConfiguring(optionsBuilder);
16 | }
17 | }
18 |
19 | public class DbContext4Sqlite2 : DataContext
20 | {
21 | public DbContext4Sqlite2(DbContextOptions options, IServiceProvider serviceProvider)
22 | : base(options, serviceProvider) { }
23 |
24 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
25 | {
26 | SetLog(optionsBuilder);
27 | optionsBuilder.UseSqlite(ConnectionString,
28 | x => x.UseNetTopologySuite());
29 | base.OnConfiguring(optionsBuilder);
30 | }
31 | }
32 |
33 | public class DbContext4Sqlite3 : DataContext
34 | {
35 | public DbContext4Sqlite3(DbContextOptions options, IServiceProvider serviceProvider)
36 | : base(options, serviceProvider) { }
37 |
38 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
39 | {
40 | SetLog(optionsBuilder);
41 | optionsBuilder.UseSqlite(ConnectionString,
42 | x => x.UseNetTopologySuite());
43 | base.OnConfiguring(optionsBuilder);
44 | }
45 | }
46 |
47 | public class DbContext4Sqlite4 : DataContext
48 | {
49 | public DbContext4Sqlite4(DbContextOptions options, IServiceProvider serviceProvider)
50 | : base(options, serviceProvider) { }
51 |
52 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
53 | {
54 | SetLog(optionsBuilder);
55 | optionsBuilder.UseSqlite(ConnectionString,
56 | x => x.UseNetTopologySuite());
57 | base.OnConfiguring(optionsBuilder);
58 | }
59 | }
60 |
61 | public class DbContext4Sqlite5 : DataContext
62 | {
63 | public DbContext4Sqlite5(DbContextOptions options, IServiceProvider serviceProvider)
64 | : base(options, serviceProvider) { }
65 |
66 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
67 | {
68 | SetLog(optionsBuilder);
69 | optionsBuilder.UseSqlite(ConnectionString,
70 | x => x.UseNetTopologySuite());
71 | base.OnConfiguring(optionsBuilder);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DefaultDataContextLoader.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Data.SqlClient;
2 | using Microsoft.Extensions.Configuration;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 |
7 | namespace EntityFrameworkCore.BootKit;
8 |
9 | public class DefaultDataContextLoader
10 | {
11 | ///
12 | /// Get data contexts implemented IDbRecord
13 | ///
14 | ///
15 | public Database GetDefaultDc()
16 | {
17 | return GetDefaultDc("Database");
18 | }
19 |
20 | public Database GetDefaultDc(string dbConfigSection)
21 | {
22 | var dc = new Database();
23 |
24 | var config = (IConfiguration)AppDomain.CurrentDomain.GetData("Configuration");
25 | var contentRootPath = AppDomain.CurrentDomain.GetData("ContentRootPath").ToString();
26 |
27 | string db = config.GetSection($"{dbConfigSection}:Default").Value;
28 | string connectionString = config.GetSection($"{dbConfigSection}:ConnectionStrings")[db];
29 |
30 | if (db.Equals("SqlServer"))
31 | {
32 | dc.BindDbContext(new DatabaseBind
33 | {
34 | MasterConnection = new SqlConnection(connectionString),
35 | CreateDbIfNotExist = true
36 | });
37 | }
38 | else if (db.Equals("InMemory"))
39 | {
40 | dc.BindDbContext(new DatabaseBind
41 | {
42 | CreateDbIfNotExist = true
43 | });
44 | }
45 |
46 | return dc;
47 | }
48 |
49 | public Database GetDefaultDc2(string dbConfigSection)
50 | {
51 | var dc = new Database();
52 |
53 | var config = (IConfiguration)AppDomain.CurrentDomain.GetData("Assemblies");
54 | var contentRootPath = AppDomain.CurrentDomain.GetData("ContentRootPath").ToString();
55 | string db = config.GetSection($"{dbConfigSection}:Default").Value;
56 | string connectionString = config.GetSection($"{dbConfigSection}:ConnectionStrings")[db];
57 |
58 | if (db.Equals("SqlServer"))
59 | {
60 | dc.BindDbContext(new DatabaseBind
61 | {
62 | MasterConnection = new SqlConnection(connectionString),
63 | CreateDbIfNotExist = true
64 | });
65 | }
66 | else if (db.Equals("InMemory"))
67 | {
68 | dc.BindDbContext(new DatabaseBind
69 | {
70 | });
71 | }
72 |
73 | return dc;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DbContexts/DataContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.Extensions.Logging;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Reflection;
6 | using System.Linq;
7 |
8 | namespace EntityFrameworkCore.BootKit
9 | {
10 | public class DataContext : DbContext
11 | {
12 | public string ConnectionString = "";
13 | public List EntityTypes { get; set; }
14 | public IServiceProvider ServiceProvider { get; set; }
15 | protected bool enableRetryOnFailure => dbSettings.EnableRetryOnFailure;
16 | protected bool useCamelCase => dbSettings.UseCamelCase;
17 |
18 |
19 | private static DatabaseSettings _dbSettings;
20 | protected DatabaseSettings dbSettings
21 | {
22 | get
23 | {
24 | if (_dbSettings == null)
25 | {
26 | if (ServiceProvider == null)
27 | {
28 | throw new Exception($"ServiceProvider is not initialized.");
29 | }
30 | _dbSettings = (DatabaseSettings)ServiceProvider.GetService(typeof(DatabaseSettings));
31 | }
32 | return _dbSettings;
33 | }
34 | }
35 |
36 | public DataContext(DbContextOptions options, IServiceProvider serviceProvider)
37 | : base(options)
38 | {
39 | ServiceProvider = serviceProvider;
40 | }
41 |
42 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
43 | {
44 | base.OnConfiguring(optionsBuilder);
45 | }
46 |
47 | protected override void OnModelCreating(ModelBuilder modelBuilder)
48 | {
49 | EntityTypes.ForEach(type =>
50 | {
51 | var type1 = modelBuilder.Model.FindEntityType(type);
52 | if(type1 == null)
53 | {
54 | modelBuilder.Model.AddEntityType(type);
55 | }
56 |
57 | if (type.GetCustomAttributes(typeof(HasNoKeyAttribute)).Any())
58 | modelBuilder.Entity(type).HasNoKey();
59 | });
60 |
61 | base.OnModelCreating(modelBuilder);
62 | }
63 |
64 | protected void SetLog(DbContextOptionsBuilder optionsBuilder)
65 | {
66 | if (ServiceProvider == null)
67 | return;
68 |
69 | if (dbSettings.EnableSqlLog)
70 | optionsBuilder.UseLoggerFactory((ILoggerFactory)ServiceProvider.GetService(typeof(ILoggerFactory)));
71 | if (dbSettings.EnableSensitiveDataLogging)
72 | optionsBuilder.EnableSensitiveDataLogging();
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DbContexts/DbContext4SqlServer.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 |
4 | namespace EntityFrameworkCore.BootKit;
5 |
6 | public class DbContext4SqlServer : DataContext
7 | {
8 | public DbContext4SqlServer(DbContextOptions options, IServiceProvider serviceProvider)
9 | : base(options, serviceProvider) { }
10 |
11 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
12 | {
13 | SetLog(optionsBuilder);
14 | optionsBuilder.UseSqlServer(ConnectionString,
15 | x =>
16 | {
17 | x.UseNetTopologySuite();
18 | if (enableRetryOnFailure)
19 | {
20 | x.EnableRetryOnFailure();
21 | }
22 | });
23 | base.OnConfiguring(optionsBuilder);
24 | }
25 | }
26 |
27 | public class DbContext4SqlServer2 : DataContext
28 | {
29 | public DbContext4SqlServer2(DbContextOptions options, IServiceProvider serviceProvider)
30 | : base(options, serviceProvider) { }
31 |
32 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
33 | {
34 | SetLog(optionsBuilder);
35 | optionsBuilder.UseSqlServer(ConnectionString,
36 | x =>
37 | {
38 | x.UseNetTopologySuite();
39 | if (enableRetryOnFailure)
40 | {
41 | x.EnableRetryOnFailure();
42 | }
43 | });
44 | base.OnConfiguring(optionsBuilder);
45 | }
46 | }
47 |
48 | public class DbContext4SqlServer3 : DataContext
49 | {
50 | public DbContext4SqlServer3(DbContextOptions options, IServiceProvider serviceProvider)
51 | : base(options, serviceProvider) { }
52 |
53 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
54 | {
55 | SetLog(optionsBuilder);
56 | optionsBuilder.UseSqlServer(ConnectionString,
57 | x =>
58 | {
59 | x.UseNetTopologySuite();
60 | if (enableRetryOnFailure)
61 | {
62 | x.EnableRetryOnFailure();
63 | }
64 | });
65 | base.OnConfiguring(optionsBuilder);
66 | }
67 | }
68 |
69 | public class DbContext4SqlServer4 : DataContext
70 | {
71 | public DbContext4SqlServer4(DbContextOptions options, IServiceProvider serviceProvider)
72 | : base(options, serviceProvider) { }
73 |
74 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
75 | {
76 | SetLog(optionsBuilder);
77 | optionsBuilder.UseSqlServer(ConnectionString,
78 | x =>
79 | {
80 | x.UseNetTopologySuite();
81 | if (enableRetryOnFailure)
82 | {
83 | x.EnableRetryOnFailure();
84 | }
85 | });
86 | base.OnConfiguring(optionsBuilder);
87 | }
88 | }
89 |
90 | public class DbContext4SqlServer5 : DataContext
91 | {
92 | public DbContext4SqlServer5(DbContextOptions options, IServiceProvider serviceProvider)
93 | : base(options, serviceProvider) { }
94 |
95 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
96 | {
97 | SetLog(optionsBuilder);
98 | optionsBuilder.UseSqlServer(ConnectionString,
99 | x =>
100 | {
101 | x.UseNetTopologySuite();
102 | if (enableRetryOnFailure)
103 | {
104 | x.EnableRetryOnFailure();
105 | }
106 | });
107 | base.OnConfiguring(optionsBuilder);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.MySql/DbContext4MySql.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace EntityFrameworkCore.BootKit;
4 |
5 | public class DbContext4MySql : DataContext
6 | {
7 | public DbContext4MySql(DbContextOptions options, IServiceProvider serviceProvider)
8 | : base(options, serviceProvider) { }
9 |
10 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
11 | {
12 | SetLog(optionsBuilder);
13 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
14 | x =>
15 | {
16 | x.UseNetTopologySuite();
17 | if (enableRetryOnFailure)
18 | {
19 | x.EnableRetryOnFailure();
20 | }
21 | });
22 | base.OnConfiguring(optionsBuilder);
23 | }
24 | }
25 |
26 | public class DbContext4MySql2 : DataContext
27 | {
28 | public DbContext4MySql2(DbContextOptions options, IServiceProvider serviceProvider)
29 | : base(options, serviceProvider) { }
30 |
31 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
32 | {
33 | SetLog(optionsBuilder);
34 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
35 | x =>
36 | {
37 | x.UseNetTopologySuite();
38 | if (enableRetryOnFailure)
39 | {
40 | x.EnableRetryOnFailure();
41 | }
42 | });
43 | base.OnConfiguring(optionsBuilder);
44 | }
45 | }
46 |
47 | public class DbContext4MySql3 : DataContext
48 | {
49 | public DbContext4MySql3(DbContextOptions options, IServiceProvider serviceProvider)
50 | : base(options, serviceProvider) { }
51 |
52 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
53 | {
54 | SetLog(optionsBuilder);
55 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
56 | x =>
57 | {
58 | x.UseNetTopologySuite();
59 | if (enableRetryOnFailure)
60 | {
61 | x.EnableRetryOnFailure();
62 | }
63 | });
64 | base.OnConfiguring(optionsBuilder);
65 | }
66 | }
67 |
68 | public class DbContext4MySql4 : DataContext
69 | {
70 | public DbContext4MySql4(DbContextOptions options, IServiceProvider serviceProvider)
71 | : base(options, serviceProvider) { }
72 |
73 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
74 | {
75 | SetLog(optionsBuilder);
76 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
77 | x =>
78 | {
79 | x.UseNetTopologySuite();
80 | if (enableRetryOnFailure)
81 | {
82 | x.EnableRetryOnFailure();
83 | }
84 | });
85 | base.OnConfiguring(optionsBuilder);
86 | }
87 | }
88 |
89 | public class DbContext4MySql5 : DataContext
90 | {
91 | public DbContext4MySql5(DbContextOptions options, IServiceProvider serviceProvider)
92 | : base(options, serviceProvider) { }
93 |
94 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
95 | {
96 | SetLog(optionsBuilder);
97 | optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString),
98 | x =>
99 | {
100 | x.UseNetTopologySuite();
101 | if (enableRetryOnFailure)
102 | {
103 | x.EnableRetryOnFailure();
104 | }
105 | });
106 | base.OnConfiguring(optionsBuilder);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.10.35027.167
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.BootKit", "EntityFrameworkCore.BootKit\EntityFrameworkCore.BootKit.csproj", "{817B600E-BD74-4A7A-AC99-37E0BBECD899}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.BootKit.UnitTest", "EntityFrameworkCore.BootKit.UnitTest\EntityFrameworkCore.BootKit.UnitTest.csproj", "{6031B9F8-88AD-4048-ACDC-7B4116155995}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.BootKit.Mongo", "EntityFrameworkCore.BootKit.Mongo\EntityFrameworkCore.BootKit.Mongo.csproj", "{7DB89166-A667-4281-9957-8D0DB9E12783}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.BootKit.Postgre", "EntityFrameworkCore.BootKit.Postgre\EntityFrameworkCore.BootKit.Postgre.csproj", "{4104673F-29DE-4084-9C9F-2355EE025686}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCore.BootKit.MySql", "EntityFrameworkCore.BootKit.MySql\EntityFrameworkCore.BootKit.MySql.csproj", "{589CE124-0B1D-4E62-B075-364F7561E90F}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCore.BootKit.Sqlite", "EntityFrameworkCore.BootKit.Sqlite\EntityFrameworkCore.BootKit.Sqlite.csproj", "{90408991-7584-40B2-96DB-02E469B20B08}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {817B600E-BD74-4A7A-AC99-37E0BBECD899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {817B600E-BD74-4A7A-AC99-37E0BBECD899}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {817B600E-BD74-4A7A-AC99-37E0BBECD899}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {817B600E-BD74-4A7A-AC99-37E0BBECD899}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {6031B9F8-88AD-4048-ACDC-7B4116155995}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {6031B9F8-88AD-4048-ACDC-7B4116155995}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {6031B9F8-88AD-4048-ACDC-7B4116155995}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {6031B9F8-88AD-4048-ACDC-7B4116155995}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {7DB89166-A667-4281-9957-8D0DB9E12783}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {7DB89166-A667-4281-9957-8D0DB9E12783}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {7DB89166-A667-4281-9957-8D0DB9E12783}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {7DB89166-A667-4281-9957-8D0DB9E12783}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {4104673F-29DE-4084-9C9F-2355EE025686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {4104673F-29DE-4084-9C9F-2355EE025686}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {4104673F-29DE-4084-9C9F-2355EE025686}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {4104673F-29DE-4084-9C9F-2355EE025686}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {589CE124-0B1D-4E62-B075-364F7561E90F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {589CE124-0B1D-4E62-B075-364F7561E90F}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {589CE124-0B1D-4E62-B075-364F7561E90F}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {589CE124-0B1D-4E62-B075-364F7561E90F}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {90408991-7584-40B2-96DB-02E469B20B08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {90408991-7584-40B2-96DB-02E469B20B08}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {90408991-7584-40B2-96DB-02E469B20B08}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {90408991-7584-40B2-96DB-02E469B20B08}.Release|Any CPU.Build.0 = Release|Any CPU
48 | EndGlobalSection
49 | GlobalSection(SolutionProperties) = preSolution
50 | HideSolutionNode = FALSE
51 | EndGlobalSection
52 | GlobalSection(ExtensibilityGlobals) = postSolution
53 | SolutionGuid = {3CC917AA-6464-4371-836E-71B3CA8029B7}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DatabaseExtensions/FactoryDatabaseExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Linq.Dynamic.Core;
7 |
8 | namespace EntityFrameworkCore.BootKit
9 | {
10 | public static class FactoryDatabaseExtension
11 | {
12 | public static int Patch(this Database db, DbPatchModel patch)
13 | {
14 | var binding = db.GetBinding(typeof(TTableInterface));
15 |
16 | var assemblies = (string[])AppDomain.CurrentDomain.GetData("Assemblies");
17 | var permissions = Utility.GetInstanceWithInterface(assemblies);
18 |
19 | var result = permissions.Any(x => !x.AllowPatch(patch));
20 |
21 | if (result) return 0;
22 |
23 | if (!String.IsNullOrEmpty(patch.Id))
24 | {
25 | var record = db.Table(patch.Table).FirstOrDefault(x => x.Id == patch.Id);
26 | SetValues(patch, record);
27 |
28 | return 1;
29 | }
30 | else
31 | {
32 | var records = db.Table(patch.Table).Where(patch.Where, patch.Params).ToList();
33 | records.ForEach(record => SetValues(patch, record));
34 |
35 | return records.Count;
36 | }
37 | }
38 |
39 | private static void SetValues(DbPatchModel patch, DbRecord record)
40 | {
41 | patch.Values.Where(x => !patch.IgnoredColumns.Contains(x.Key))
42 | .ToList()
43 | .ForEach(x =>
44 | {
45 | try
46 | {
47 | record.SetValue(x.Key, x.Value);
48 | }
49 | catch (Exception ex)
50 | {
51 | Console.WriteLine($"Set value exception: {x.Key} {x.Value}");
52 | throw ex;
53 | }
54 | });
55 | }
56 |
57 | public static IQueryable Table(this Database db, string tableName)
58 | {
59 | return Table(db, tableName);
60 | }
61 |
62 | public static IQueryable Table(this Database db, string tableName)
63 | {
64 | var binding = db.GetBinding(tableName);
65 |
66 | var tableType = binding.Entities.First(x => x.Name.ToLower().Equals(tableName.ToLower()));
67 |
68 | if (tableType == null) return null;
69 |
70 | DbContext dc = null;
71 |
72 | if (binding.DbContextMaster != null && binding.DbContextMaster.Database.CurrentTransaction != null)
73 | {
74 | dc = db.GetMaster(tableType);
75 | }
76 | else
77 | {
78 | dc = db.GetReader(tableType);
79 | }
80 |
81 | var dbSet = (IQueryable)dc.GetType()
82 | .GetMethod("Set").MakeGenericMethod(tableType)
83 | .Invoke(dc, null);
84 |
85 | return dbSet;
86 | }
87 |
88 | public static object Add(this Database db, string table, Object entity)
89 | {
90 | var dbSet = db.Table(table);
91 |
92 | var assemblies = (string[])AppDomain.CurrentDomain.GetData("Assemblies");
93 | var tableType = Utility.GetType(table, assemblies);
94 |
95 | return dbSet.InvokeFunction("Add", new Object[] { entity });
96 | }
97 |
98 | public static object Remove(this Database db, string table, Object entity)
99 | {
100 | var dbSet = db.Table(table);
101 |
102 | var assemblies = (string[])AppDomain.CurrentDomain.GetData("Assemblies");
103 | var tableType = Utility.GetType(table, assemblies);
104 |
105 | return dbSet.InvokeFunction("Remove", new Object[] { entity });
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EntityFrameworkCore.BootKit
2 | n']
3 | [](https://gitter.im/sci-sharp/community) [](https://tensorflownet.readthedocs.io/en/latest/?badge=latest) [](https://www.nuget.org/packages/EntityFrameworkCore.BootKit)
4 |
5 | EntityFrameworkCore Boot Kit (EFBK) is a quick start database connect library for using .NET EntityFrameworkCore.
6 |
7 | ### Features:
8 |
9 | * Inherits from EntityFrameworkCore Triggers to enable entries update notfication.
10 | * Support mulitple databases like MySql, SQL Server, Sqlite, PostgreSql, MongoDB, Amazon Redshift, AWS Aurora and InMemory.
11 | * Support dynamic linq to query and update database.
12 | * Support read/write seperated mode. Randomly choose multiple slaves.
13 | * Multiple database with distributed transaction supported, and MySQL multiple databases/tables sharding supported.
14 | * Tracking entry change history.
15 | * Built-in DbFactory with access control list (ACL) hook.
16 |
17 | ### Get started
18 |
19 | How to install
20 |
21 | ```sh
22 | PM> Install-Package EntityFrameworkCore.BootKit
23 | ```
24 |
25 | How to use
26 |
27 | 1. Define entity
28 |
29 |
30 | ```cs
31 | public class PizzaOrder : DbRecord, IDbRecord
32 | {
33 | [MaxLength(32)]
34 | public String OrderNumber { get; set; }
35 |
36 | [MaxLength(64)]
37 | public String CustomerName { get; set; }
38 |
39 | [Required]
40 | public DateTime CreatedTime { get; set; }
41 |
42 | [ForeignKey("OrderId")]
43 | public List PizzaTypes { get; set; }
44 | }
45 | ```
46 |
47 | 2. Init data context
48 |
49 | ```cs
50 | var db = new Database();
51 | AppDomain.CurrentDomain.SetData("Assemblies", new string[] { "EntityFrameworkCore.BootKit.UnitTest" });
52 |
53 | // bind as much data context as you can
54 | db.BindDbContext(new DatabaseBind
55 | {
56 | MasterConnection = new SqliteConnection($"Data Source={Directory.GetCurrentDirectory()}\\..\\..\\..\\..\\bootkit.db"),
57 | CreateDbIfNotExist = true
58 | });
59 |
60 | db.BindDbContext(new DatabaseBind
61 | {
62 | MasterConnection = new NpgsqlConnection("Server=; Port=5439;User ID=;Password=;Database=;SSL Mode=Require;Trust Server Certificate=True;Use SSL Stream=True"),
63 | });
64 | ```
65 |
66 | 3. Retrieve record
67 |
68 | ```cs
69 | var order = db.Table().Include(x => x.PizzaTypes).FirstOrDefault();
70 | ```
71 |
72 | 4. Retrieve record by table name
73 |
74 | ```cs
75 | var table = db.Table("PizzaOrder");
76 | var pizzaOrder = table.First() as PizzaOrder;
77 | ```
78 |
79 | 5. Update record in transaction
80 |
81 | ```cs
82 | int row = db.DbTran(() =>
83 | {
84 | var po = db.Table().Find(PIZZA_ORDER_ID);
85 | po.CreatedTime = DateTime.UtcNow
86 | });
87 | ```
88 |
89 | 6. Update record in Patch function
90 |
91 | ```cs
92 | int row = db.DbTran(() =>
93 | {
94 | var patch = new DbPatchModel
95 | {
96 | Table = "PizzaOrder",
97 | Id = PIZZA_ORDER_ID
98 | };
99 |
100 | patch.Values.Add("CreatedTime", dt);
101 | db.Patch(patch);
102 | });
103 | ```
104 |
105 | 7. Implement IRequireDbPermission to interupt update
106 | 8. View raw sql
107 |
108 | ```cs
109 | string sql = table.ToSql();
110 | ```
111 |
112 | 9. Added MongoDb support
113 |
114 | ```cs
115 | db.BindDbContext(new DatabaseBind
116 | {
117 | MasterConnection = new MongoDbConnection("mongodb://user:password@localhost:27017/db"),
118 | });
119 | var collection = db.Collection().FirstOrDefault();
120 |
121 | // Add new record
122 | db.Collection().InsertOne(new MongoDbCollection
123 | {
124 | Id = Guid.NewGuid().ToString(),
125 | Name = "Pizza"
126 | });
127 |
128 | // Update record
129 | db.Collection().UpdateOne(x => x.Name == "Pizza", x => x.Name, "Pizza 2");
130 | ```
131 |
132 | 10. Support Amazon Redshift
133 |
134 | ```cs
135 | db.BindDbContext(new DatabaseBind
136 | {
137 | string connString = "Server=*.us-east-1.redshift.amazonaws.com; Port=5439;User ID=;Password=;Database=;Server Compatibility Mode=Redshift;SSL Mode=Require;Trust Server Certificate=True;Use SSL Stream=True";
138 | MasterConnection = new NpgsqlConnection(connString),
139 | });
140 | ```
141 |
142 | ### Documentation
143 |
144 | https://entityframeworkcorebootkit.readthedocs.io
145 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/EntityFrameworkCore.BootKit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(LangVersion)
5 |
6 |
7 |
8 | net10.0;net8.0;net6.0;netstandard2.1
9 | $(GeneratePackageOnBuild)
10 | EntityFrameworkCore Boot Kit (EFBK) is a quick start database connecter for using EntityFrameworkCore.
11 | Support variety of databases such as Sqlite, MySql, SqlServer, PostgreSql, MongoDb, Amazon Redshift, AWS Aurora and Memory database.
12 | https://github.com/Oceania2018/EntityFrameworkCore.BootKit
13 | https://github.com/Oceania2018/EntityFrameworkCore.BootKit
14 | EntityFramework, EntityFrameworkCore, Database, Redshift, Aurora, Postgre, MySql, MongoDB
15 | Haiping Chen
16 | SciSharp STACK
17 | $(BootKitVersion)
18 | 1. Upgrade to EF 10.0.
19 |
20 | $(BootKitVersion)
21 | $(BootKitVersion)
22 | Apache 2.0
23 | git
24 | https://avatars3.githubusercontent.com/u/44989469?s=200&v=4
25 | MIT
26 |
27 |
28 |
29 | TRACE;DEBUG
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Mongo/DbContext4MongoDb.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using MongoDB.Bson.Serialization.Conventions;
3 | using MongoDB.Driver;
4 | using System;
5 | using System.Linq;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace EntityFrameworkCore.BootKit;
9 |
10 | public class DbContext4MongoDb : DataContext
11 | {
12 | private static bool _isRegisteredConvention = false;
13 |
14 | public DbContext4MongoDb(DbContextOptions options, IServiceProvider serviceProvider)
15 | : base(options, serviceProvider) { }
16 |
17 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
18 | {
19 | SetLog(optionsBuilder);
20 | optionsBuilder.UseMongoDb(ConnectionString);
21 | base.OnConfiguring(optionsBuilder);
22 | }
23 |
24 | public new IMongoCollection Set(string name = "")
25 | {
26 | return GetDatabase().GetCollection(String.IsNullOrEmpty(name) ? typeof(TEntity).Name : name);
27 | }
28 |
29 | public IMongoDatabase GetDatabase()
30 | {
31 | string databaseName = ConnectionString.Split('/').Last().Split('?').First();
32 |
33 | /*MongoClientSettings settings = new MongoClientSettings();
34 | settings.ConnectTimeout = new TimeSpan(0, 0, 0, 30, 0);
35 | settings.ConnectionMode = ConnectionMode.Direct;
36 |
37 | string server = new Regex("@.+/").Match(ConnectionString).Value.Substring(1);
38 | string host = server.Split(':').First();
39 | string userName = new Regex("//[^@]+").Match(ConnectionString).Value.Split(':').First().Substring(2);
40 | string password = new Regex("//[^@]+").Match(ConnectionString).Value.Split(':').Last();
41 |
42 | MongoCredential credential = MongoCredential.CreateCredential(databaseName, userName, password);
43 | settings.Credential = credential;
44 |
45 | settings.Server = new MongoServerAddress(host);*/
46 |
47 | MongoClient client = new MongoClient(ConnectionString);
48 |
49 | IMongoDatabase database = client.GetDatabase(databaseName);
50 |
51 | // Prevent ConventionRegistry to keep growing
52 | if (!_isRegisteredConvention)
53 | {
54 | var packs = new ConventionPack
55 | {
56 | new IgnoreExtraElementsConvention(true)
57 | };
58 |
59 | if (useCamelCase)
60 | {
61 | packs.Add(new CamelCaseElementNameConvention());
62 | }
63 |
64 | ConventionRegistry.Register("EntityFrameworkCore.BootKit", packs, t => true);
65 | _isRegisteredConvention = true;
66 | }
67 |
68 | return database;
69 | }
70 | }
71 |
72 | public class DbContext4MongoDb2 : DataContext
73 | {
74 | private static bool _isRegisteredIgnoreExtraElementsConvention = false;
75 |
76 | public DbContext4MongoDb2(DbContextOptions options, IServiceProvider serviceProvider)
77 | : base(options, serviceProvider) { }
78 |
79 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
80 | {
81 | SetLog(optionsBuilder);
82 | optionsBuilder.UseMongoDb(ConnectionString);
83 | base.OnConfiguring(optionsBuilder);
84 | }
85 |
86 | public new IMongoCollection Set(string name = "")
87 | {
88 | return GetDatabase().GetCollection(String.IsNullOrEmpty(name) ? typeof(TEntity).Name : name);
89 | }
90 |
91 | public IMongoDatabase GetDatabase()
92 | {
93 | string databaseName = ConnectionString.Split('/').Last();
94 |
95 | MongoClientSettings settings = new MongoClientSettings();
96 | settings.ConnectTimeout = new TimeSpan(0, 0, 0, 30, 0);
97 | settings.DirectConnection = true;
98 |
99 | string server = new Regex("@.+/").Match(ConnectionString).Value.Substring(1);
100 | string host = server.Split(':').First();
101 | string userName = new Regex("//[^@]+").Match(ConnectionString).Value.Split(':').First().Substring(2);
102 | string password = new Regex("//[^@]+").Match(ConnectionString).Value.Split(':').Last();
103 |
104 | MongoCredential credential = MongoCredential.CreateCredential(databaseName, userName, password);
105 | settings.Credential = credential;
106 |
107 | settings.Server = new MongoServerAddress(host);
108 |
109 | MongoClient client = new MongoClient(settings);
110 |
111 | IMongoDatabase database = client.GetDatabase(databaseName);
112 |
113 | // Prevent ConventionRegistry to keep growing
114 | if (!_isRegisteredIgnoreExtraElementsConvention)
115 | {
116 | var pack = new ConventionPack();
117 | pack.Add(new IgnoreExtraElementsConvention(true));
118 | ConventionRegistry.Register("EntityFrameworkCore.BootKit", pack, t => true);
119 | _isRegisteredIgnoreExtraElementsConvention = true;
120 | }
121 |
122 | return database;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.Mongo/MongoDbQueryExtension.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Driver;
2 | using MongoDB.Driver.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Linq.Dynamic.Core;
7 | using System.Linq.Expressions;
8 |
9 | namespace EntityFrameworkCore.BootKit;
10 |
11 | public static class MongoDbQueryExtension
12 | {
13 | public static IQueryable Queryable(this IMongoCollection source)
14 | {
15 | return source.AsQueryable();
16 | }
17 |
18 | public static TSource FirstOrDefault(this IMongoCollection source, Expression> filter = null)
19 | {
20 | return filter == null ? source.Queryable().FirstOrDefault() : source.Queryable().FirstOrDefault(filter);
21 | }
22 |
23 | public static TSource LastOrDefault(this IMongoCollection source, Expression> filter = null)
24 | {
25 | throw new NotSupportedException("MongoDB does not support LastOrDefault() method.");
26 | // return filter == null ? source.Queryable().LastOrDefault() : source.Queryable().LastOrDefault(filter);
27 | }
28 |
29 | public static IOrderedQueryable OrderByDescending(this IMongoCollection source, Expression> keySelector)
30 | {
31 | return source.Queryable().OrderByDescending(keySelector);
32 | }
33 |
34 | public static IQueryable Where(this IMongoCollection source, Expression> filter)
35 | {
36 | return source.Queryable().Where(filter);
37 | }
38 |
39 | public static UpdateResult UpdateOne(this IMongoCollection source,
40 | Expression> filter,
41 | Expression> field,
42 | TField value)
43 | {
44 | return source.UpdateOne(filter, Builders.Update.Set(field, value));
45 | }
46 |
47 | public static UpdateResult UpdateOne(this IMongoCollection source,
48 | Expression> filter,
49 | (Expression>, object)[] kvs)
50 | {
51 | var updateDefinitionBuilder = Builders.Update;
52 | var definitions = new List>();
53 | foreach (var pair in kvs)
54 | {
55 | definitions.Add(updateDefinitionBuilder.Set(pair.Item1, pair.Item2));
56 | }
57 |
58 | var updateFields = updateDefinitionBuilder.Combine(definitions);
59 |
60 | return source.UpdateOne(filter, updateFields);
61 | }
62 |
63 | public static UpdateResult UpsetOne(this IMongoCollection source,
64 | Expression> filter,
65 | Expression> field,
66 | TField value)
67 | {
68 | return source.UpdateOne(filter, Builders.Update.Set(field, value), options: new UpdateOptions
69 | {
70 | IsUpsert = true
71 | });
72 | }
73 |
74 | public static UpdateResult UpsertOne(this IMongoCollection source,
75 | Expression> filter,
76 | (Expression>, TField1)[] kvs)
77 | {
78 | var updateDefinitionBuilder = Builders.Update;
79 | var definitions = new List>();
80 | foreach (var pair in kvs)
81 | {
82 | definitions.Add(updateDefinitionBuilder.Set(pair.Item1, pair.Item2));
83 | }
84 |
85 | var updateFields = updateDefinitionBuilder.Combine(definitions);
86 |
87 | return source.UpdateOne(filter, updateFields, options: new UpdateOptions
88 | {
89 | IsUpsert = true
90 | });
91 | }
92 |
93 | public static UpdateResult UpdateMany(this IMongoCollection source,
94 | Expression> filter,
95 | Expression> field,
96 | TField value)
97 | {
98 | return source.UpdateMany(filter, Builders.Update.Set(field, value));
99 | }
100 |
101 | public static UpdateResult UpsertMany(this IMongoCollection source,
102 | Expression> filter,
103 | Expression> field,
104 | TField value)
105 | {
106 | return source.UpdateMany(filter, Builders.Update.Set(field, value), options: new UpdateOptions
107 | {
108 | IsUpsert = true
109 | });
110 | }
111 |
112 | public static DeleteResult DeleteOne(this IMongoCollection source,
113 | Expression> filter)
114 | {
115 | return source.DeleteOne(filter);
116 | }
117 |
118 | public static DeleteResult DeleteMany(this IMongoCollection source,
119 | Expression> filter)
120 | {
121 | return source.DeleteMany(filter);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Utility.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 |
7 | namespace EntityFrameworkCore.BootKit
8 | {
9 | public static class Utility
10 | {
11 | public static Type GetType(String typeName, params string[] assemblyNames)
12 | {
13 | for (int i = 0; i < assemblyNames.Count(); i++)
14 | {
15 | List types = Assembly.Load(new AssemblyName(assemblyNames[i]))
16 | .GetTypes().Where(x => !x.IsAbstract && !x.FullName.StartsWith("<>f__AnonymousType")).ToList();
17 |
18 | Type type = types.FirstOrDefault(x => x.Name == typeName);
19 | if (type != null)
20 | {
21 | return type;
22 | };
23 | }
24 |
25 | return null;
26 | }
27 |
28 | public static List GetClassesWithInterface(Type type, string assemblyName)
29 | {
30 | List types = Assembly.Load(new AssemblyName(assemblyName))
31 | .GetTypes()
32 | .Where(x => !x.IsAbstract && !x.FullName.StartsWith("<>f__AnonymousType"))
33 | .ToList();
34 |
35 | types = types.Where(x => !x.GetTypeInfo().IsAbstract && x.GetInterfaces().Contains(type)).ToList();
36 |
37 | return types;
38 | }
39 |
40 | public static List GetClassesWithInterface(Type type, params string[] assemblyNames)
41 | {
42 | List types = new List();
43 | assemblyNames.ToList().ForEach(assemblyName => {
44 | types.AddRange(GetClassesWithInterface(type, assemblyName));
45 | });
46 |
47 | return types;
48 | }
49 |
50 | public static List GetInstanceWithInterface(params string[] assemblyNames)
51 | {
52 | List instances = new List();
53 |
54 | var types = GetClassesWithInterface(typeof(T), assemblyNames);
55 | var objects = types.Where(x => x.GetInterfaces().Contains(typeof(T))).Select(x => (T)Activator.CreateInstance(x)).ToList();
56 | instances.AddRange(objects);
57 |
58 | return instances;
59 | }
60 |
61 | public static object InvokeFunction(this object obj, string methodName, object[] parameters)
62 | {
63 | Type type = obj.GetType();
64 | MethodInfo method = type.GetMethod(methodName);
65 | return method.Invoke(obj, parameters);
66 | }
67 |
68 | public static bool SetValue(this object obj, string propName, object value)
69 | {
70 | Type type = obj.GetType();
71 | PropertyInfo property = type.GetProperties().FirstOrDefault(x => x.Name.ToLower().Equals(propName.ToLower()));
72 | if (property == null) return false;
73 |
74 | if (property.PropertyType.Equals(typeof(String)))
75 | {
76 | property.SetValue(obj, value.ToString(), null);
77 | }
78 | else if (property.PropertyType.Equals(typeof(DateTime)) && value.GetType() == typeof(string))
79 | {
80 | property.SetValue(obj, DateTime.Parse(value.ToString()), null);
81 | }
82 | else if (property.PropertyType.Equals(typeof(Int32)) && value.GetType() == typeof(string))
83 | {
84 | property.SetValue(obj, Int32.Parse(value.ToString()), null);
85 | }
86 | /*else if (property.PropertyType.IsEnum)
87 | {
88 | property.SetValue(obj, int.Parse(value.ToString()), null);
89 | }
90 | else if (property.PropertyType.IsGenericType && Nullable.GetUnderlyingType(property.PropertyType) != null && Nullable.GetUnderlyingType(property.PropertyType).IsEnum)
91 | {
92 | var enumType = Nullable.GetUnderlyingType(property.PropertyType);
93 | var enumValue = Enum.ToObject(enumType, value);
94 | property.SetValue(obj, enumValue, null);
95 | }
96 | else if (property.PropertyType.IsGenericType && Nullable.GetUnderlyingType(property.PropertyType) != null && Nullable.GetUnderlyingType(property.PropertyType).Equals(typeof(int)))
97 | {
98 | property.SetValue(obj, int.Parse(value.ToString()), null);
99 | }*/
100 | else if (property.PropertyType.IsGenericType && Nullable.GetUnderlyingType(property.PropertyType) != null && Nullable.GetUnderlyingType(property.PropertyType).Equals(typeof(decimal)))
101 | {
102 | if (String.IsNullOrEmpty(value.ToString()))
103 | {
104 | property.SetValue(obj, null);
105 | }
106 | else
107 | {
108 | property.SetValue(obj, decimal.Parse(value.ToString()));
109 | }
110 | }
111 | else if (property.PropertyType.Equals(typeof(Decimal)))
112 | {
113 | property.SetValue(obj, decimal.Parse(value.ToString()));
114 | }
115 | else
116 | {
117 | property.SetValue(obj, value, null);
118 | }
119 |
120 | return true;
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # EntityFrameworkCore.BootKit documentation build configuration file, created by
5 | # sphinx-quickstart on Tue Aug 21 16:39:58 2018.
6 | #
7 | # This file is execfile()d with the current directory set to its
8 | # containing dir.
9 | #
10 | # Note that not all possible configuration values are present in this
11 | # autogenerated file.
12 | #
13 | # All configuration values have a default; values that are commented out
14 | # serve to show the default.
15 |
16 | # If extensions (or modules to document with autodoc) are in another directory,
17 | # add these directories to sys.path here. If the directory is relative to the
18 | # documentation root, use os.path.abspath to make it absolute, like shown here.
19 | #
20 | # import os
21 | # import sys
22 | # sys.path.insert(0, os.path.abspath('.'))
23 |
24 |
25 | # -- General configuration ------------------------------------------------
26 |
27 | # If your documentation needs a minimal Sphinx version, state it here.
28 | #
29 | # needs_sphinx = '1.0'
30 |
31 | # Add any Sphinx extension module names here, as strings. They can be
32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33 | # ones.
34 | extensions = []
35 |
36 | # Add any paths that contain templates here, relative to this directory.
37 | templates_path = ['_templates']
38 |
39 | # The suffix(es) of source filenames.
40 | # You can specify multiple suffix as a list of string:
41 | #
42 | # source_suffix = ['.rst', '.md']
43 | source_suffix = '.rst'
44 |
45 | # The master toctree document.
46 | master_doc = 'index'
47 |
48 | # General information about the project.
49 | project = 'EntityFrameworkCore.BootKit'
50 | copyright = '2018, Haiping Chen'
51 | author = 'Haiping Chen'
52 |
53 | # The version info for the project you're documenting, acts as replacement for
54 | # |version| and |release|, also used in various other places throughout the
55 | # built documents.
56 | #
57 | # The short X.Y version.
58 | version = '1.9.1'
59 | # The full version, including alpha/beta/rc tags.
60 | release = '1.9.1'
61 |
62 | # The language for content autogenerated by Sphinx. Refer to documentation
63 | # for a list of supported languages.
64 | #
65 | # This is also used if you do content translation via gettext catalogs.
66 | # Usually you set "language" from the command line for these cases.
67 | language = None
68 |
69 | # List of patterns, relative to source directory, that match files and
70 | # directories to ignore when looking for source files.
71 | # This patterns also effect to html_static_path and html_extra_path
72 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
73 |
74 | # The name of the Pygments (syntax highlighting) style to use.
75 | pygments_style = 'sphinx'
76 |
77 | # If true, `todo` and `todoList` produce output, else they produce nothing.
78 | todo_include_todos = False
79 |
80 |
81 | # -- Options for HTML output ----------------------------------------------
82 |
83 | # The theme to use for HTML and HTML Help pages. See the documentation for
84 | # a list of builtin themes.
85 | #
86 | html_theme = 'sphinx_rtd_theme'
87 |
88 | # Theme options are theme-specific and customize the look and feel of a theme
89 | # further. For a list of options available for each theme, see the
90 | # documentation.
91 | #
92 | # html_theme_options = {}
93 |
94 | # Add any paths that contain custom static files (such as style sheets) here,
95 | # relative to this directory. They are copied after the builtin static files,
96 | # so a file named "default.css" will overwrite the builtin "default.css".
97 | html_static_path = ['_static']
98 |
99 | # Custom sidebar templates, must be a dictionary that maps document names
100 | # to template names.
101 | #
102 | # This is required for the alabaster theme
103 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
104 | html_sidebars = {
105 | '**': [
106 | 'relations.html', # needs 'show_related': True theme option to display
107 | 'searchbox.html',
108 | ]
109 | }
110 |
111 |
112 | # -- Options for HTMLHelp output ------------------------------------------
113 |
114 | # Output file base name for HTML help builder.
115 | htmlhelp_basename = 'EntityFrameworkCoreBootKitdoc'
116 |
117 |
118 | # -- Options for LaTeX output ---------------------------------------------
119 |
120 | latex_elements = {
121 | # The paper size ('letterpaper' or 'a4paper').
122 | #
123 | # 'papersize': 'letterpaper',
124 |
125 | # The font size ('10pt', '11pt' or '12pt').
126 | #
127 | # 'pointsize': '10pt',
128 |
129 | # Additional stuff for the LaTeX preamble.
130 | #
131 | # 'preamble': '',
132 |
133 | # Latex figure (float) alignment
134 | #
135 | # 'figure_align': 'htbp',
136 | }
137 |
138 | # Grouping the document tree into LaTeX files. List of tuples
139 | # (source start file, target name, title,
140 | # author, documentclass [howto, manual, or own class]).
141 | latex_documents = [
142 | (master_doc, 'EntityFrameworkCoreBootKit.tex', 'EntityFrameworkCore.BootKit Documentation',
143 | 'Haiping Chen', 'manual'),
144 | ]
145 |
146 |
147 | # -- Options for manual page output ---------------------------------------
148 |
149 | # One entry per manual page. List of tuples
150 | # (source start file, name, description, authors, manual section).
151 | man_pages = [
152 | (master_doc, 'entityframeworkcorebootkit', 'EntityFrameworkCore.BootKit Documentation',
153 | [author], 1)
154 | ]
155 |
156 |
157 | # -- Options for Texinfo output -------------------------------------------
158 |
159 | # Grouping the document tree into Texinfo files. List of tuples
160 | # (source start file, target name, title, author,
161 | # dir menu entry, description, category)
162 | texinfo_documents = [
163 | (master_doc, 'EntityFrameworkCoreBootKit', 'EntityFrameworkCore.BootKit Documentation',
164 | author, 'EntityFrameworkCoreBootKit', 'One line description of project.',
165 | 'Miscellaneous'),
166 | ]
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 | /bootkit.db
290 | /docs/_build
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/DatabaseExtensions/TransactionDatabaseExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Infrastructure;
3 | using Microsoft.EntityFrameworkCore.Storage;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace EntityFrameworkCore.BootKit
10 | {
11 | public static class TransactionDatabaseExtension
12 | {
13 | public static DatabaseFacade GetDatabaseFacade(this Database db)
14 | => db.GetMaster(typeof(TTableInterface)).Database;
15 | public static IDbContextTransaction BeginTransaction(this Database db)
16 | {
17 | var masterDb = db.GetMaster(typeof(TTableInterface)).Database;
18 | if (masterDb.CurrentTransaction == null)
19 | return masterDb.BeginTransaction();
20 | else
21 | return masterDb.CurrentTransaction;
22 | }
23 |
24 | public static void RollbackTransaction(this Database db)
25 | {
26 | var masterDb = db.GetMaster(typeof(TTableInterface)).Database;
27 | if (masterDb.CurrentTransaction != null)
28 | masterDb.RollbackTransaction();
29 | }
30 |
31 | public static void EndTransaction(this Database db)
32 | {
33 | var masterDb = db.GetMaster(typeof(TTableInterface)).Database;
34 | // current transaction will be null if it's been rollbacked.
35 | if (masterDb.CurrentTransaction == null)
36 | return;
37 | try
38 | {
39 | db.SaveChanges();
40 | masterDb.CurrentTransaction.Commit();
41 | }
42 | catch (Exception ex)
43 | {
44 | masterDb.CurrentTransaction.Rollback();
45 | if (ex.Message.Contains("See the inner exception for details"))
46 | throw ex.InnerException;
47 | else
48 | throw ex;
49 | }
50 | }
51 |
52 | public static void DiscardChanges(DbContext context)
53 | {
54 | // Clear Change Tracker to discard changes
55 | // Available in EF Core 7+
56 | #if NET8_0_OR_GREATER
57 | context.ChangeTracker.Clear();
58 | #else
59 | foreach (var entry in context.ChangeTracker.Entries())
60 | {
61 | entry.State = EntityState.Detached;
62 | }
63 | #endif
64 | }
65 |
66 | public static int Transaction(this Database db, Action action)
67 | {
68 | var dbContext = db.GetMaster(typeof(TTableInterface));
69 | var masterDb = dbContext.Database;
70 | int affected = 0;
71 |
72 | if (masterDb.CurrentTransaction == null)
73 | {
74 | using (var transaction = masterDb.BeginTransaction())
75 | {
76 | try
77 | {
78 | action();
79 | affected = db.SaveChanges();
80 | transaction.Commit();
81 | }
82 | catch (Exception ex)
83 | {
84 | transaction.Rollback();
85 | DiscardChanges(dbContext);
86 | if (ex.Message.Contains("See the inner exception for details"))
87 | throw ex.InnerException;
88 | else
89 | throw ex;
90 | }
91 | }
92 | }
93 | else
94 | {
95 | try
96 | {
97 | action();
98 | affected = db.SaveChanges();
99 | }
100 | catch (Exception ex)
101 | {
102 | if (masterDb.CurrentTransaction != null)
103 | {
104 | masterDb.CurrentTransaction.Rollback();
105 | DiscardChanges(dbContext);
106 | }
107 | if (ex.Message.Contains("See the inner exception for details"))
108 | throw ex.InnerException;
109 | else
110 | throw ex;
111 | }
112 | }
113 |
114 | return affected;
115 | }
116 |
117 | public static TResult Transaction(this Database db, Func action)
118 | {
119 | using (IDbContextTransaction transaction = db.GetMaster(typeof(T)).Database.BeginTransaction())
120 | {
121 | TResult result = default(TResult);
122 | try
123 | {
124 | result = action();
125 | db.SaveChanges();
126 | transaction.Commit();
127 | }
128 | catch (Exception ex)
129 | {
130 | transaction.Rollback();
131 | if (ex.Message.Contains("See the inner exception for details"))
132 | throw ex.InnerException;
133 | else
134 | throw ex;
135 | }
136 |
137 | return result;
138 | }
139 | }
140 |
141 | public static async Task TransactionAsync(this Database db, Func func)
142 | {
143 | var masterDb = db.GetMaster(typeof(TTableInterface)).Database;
144 | int affected = 0;
145 | if (masterDb.CurrentTransaction == null)
146 | {
147 | using (var transaction = await masterDb.BeginTransactionAsync())
148 | {
149 | try
150 | {
151 | await func();
152 | affected = await db.SaveChangesAsync();
153 | await transaction.CommitAsync();
154 | }
155 | catch (Exception ex)
156 | {
157 | await transaction.RollbackAsync();
158 | if (ex.Message.Contains("See the inner exception for details"))
159 | throw ex.InnerException;
160 | else throw ex;
161 | }
162 | }
163 | }
164 | else
165 | {
166 | try
167 | {
168 | await func();
169 | affected = await db.SaveChangesAsync();
170 | }
171 | catch (Exception ex)
172 | {
173 | if (masterDb.CurrentTransaction != null)
174 | await masterDb.CurrentTransaction.RollbackAsync();
175 | else if (ex.Message.Contains("See the inner exception for details"))
176 | throw ex.InnerException;
177 | else throw ex;
178 | }
179 | }
180 | return affected;
181 | }
182 |
183 | public static async Task TransactionAsync(this Database db, Func> func)
184 | {
185 | using (IDbContextTransaction transaction = await db.GetMaster(typeof(T)).Database.BeginTransactionAsync())
186 | {
187 | TResult result = default;
188 | try
189 | {
190 | result = await func();
191 | await db.SaveChangesAsync();
192 | await transaction.CommitAsync();
193 | }
194 | catch (Exception ex)
195 | {
196 | await transaction.RollbackAsync();
197 | if (ex.Message.Contains("See the inner exception for details"))
198 | throw ex.InnerException;
199 | else
200 | throw ex;
201 | }
202 | return result;
203 | }
204 | }
205 |
206 | ///
207 | /// Shortcut for IDbRecord Transaction
208 | ///
209 | ///
210 | ///
211 | public static int DbTran(this Database db, Action action)
212 | {
213 | return db.Transaction(action);
214 | }
215 |
216 | public static IDbContextTransaction GetDbContextTransaction(this Database db)
217 | {
218 | var masterDb = db.GetMaster(typeof(T)).Database;
219 |
220 | if (masterDb.CurrentTransaction == null)
221 | return masterDb.BeginTransaction();
222 | else
223 | return masterDb.CurrentTransaction;
224 | }
225 |
226 | public static bool IsTransactionOpen(this Database db)
227 | {
228 | var masterDb = db.GetMaster(typeof(T)).Database;
229 | return masterDb.CurrentTransaction != null;
230 | }
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit.UnitTest/DatabaseTest.cs:
--------------------------------------------------------------------------------
1 | using EntityFrameworkCore.BootKit.DbContexts;
2 | using EntityFrameworkCore.BootKit.Sqlite;
3 | using EntityFrameworkCore.BootKit.UnitTest.Tables;
4 | using Microsoft.Data.SqlClient;
5 | using Microsoft.Data.Sqlite;
6 | using Microsoft.EntityFrameworkCore;
7 | using Microsoft.VisualStudio.TestTools.UnitTesting;
8 | using MySqlConnector;
9 | using Npgsql;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.IO;
13 | using System.Linq;
14 |
15 | namespace EntityFrameworkCore.BootKit.UnitTest;
16 |
17 | [TestClass]
18 | public class DatabaseTest
19 | {
20 | [TestMethod]
21 | public void TestSqlite()
22 | {
23 | AddRecord(GetDb(DatabaseType.Sqlite));
24 | AddRecordByTableName(GetDb(DatabaseType.Sqlite));
25 | GetRecordsByTableName(GetDb(DatabaseType.Sqlite));
26 | UpdateRecordsByTableName(GetDb(DatabaseType.Sqlite));
27 | PatchRecord(GetDb(DatabaseType.Sqlite));
28 | }
29 |
30 | [TestMethod]
31 | public void TestSqlServer()
32 | {
33 | AddRecord(GetDb(DatabaseType.SqlServer));
34 | AddRecordByTableName(GetDb(DatabaseType.SqlServer));
35 | GetRecordsByTableName(GetDb(DatabaseType.SqlServer));
36 | UpdateRecordsByTableName(GetDb(DatabaseType.SqlServer));
37 | PatchRecord(GetDb(DatabaseType.SqlServer));
38 | }
39 |
40 | [TestMethod]
41 | public void TestMySql()
42 | {
43 | AddRecord(GetDb(DatabaseType.MySql));
44 | AddRecordByTableName(GetDb(DatabaseType.MySql));
45 | GetRecordsByTableName(GetDb(DatabaseType.MySql));
46 | UpdateRecordsByTableName(GetDb(DatabaseType.MySql));
47 | PatchRecord(GetDb(DatabaseType.MySql));
48 | }
49 |
50 | [TestMethod]
51 | public void TestPostgreSql()
52 | {
53 | AddRecord(GetDb(DatabaseType.PostgreSql));
54 | AddRecordByTableName(GetDb(DatabaseType.PostgreSql));
55 | GetRecordsByTableName(GetDb(DatabaseType.PostgreSql));
56 | UpdateRecordsByTableName(GetDb(DatabaseType.PostgreSql));
57 | PatchRecord(GetDb(DatabaseType.PostgreSql));
58 | }
59 |
60 | [TestMethod]
61 | public void TestRedshift()
62 | {
63 | AddRecord(GetDb(DatabaseType.Redshift));
64 | AddRecordByTableName(GetDb(DatabaseType.Redshift));
65 | GetRecordsByTableName(GetDb(DatabaseType.Redshift));
66 | UpdateRecordsByTableName(GetDb(DatabaseType.Redshift));
67 | PatchRecord(GetDb(DatabaseType.Redshift));
68 | }
69 |
70 | [TestMethod]
71 | public void TestMongoDb()
72 | {
73 | var db = GetDb(DatabaseType.MongoDb);
74 | var collection = db.Collection().FirstOrDefault();
75 |
76 | // Add new record
77 | db.Collection().InsertOne(new MongoDbCollection
78 | {
79 | Id = Guid.NewGuid().ToString(),
80 | Name = "Pizza"
81 | });
82 |
83 | // Update record
84 | db.Collection().UpdateOne(x => x.Name == "Pizza", x => x.Name, "Pizza 2");
85 | }
86 |
87 | [TestMethod]
88 | public void TestRawQuery()
89 | {
90 | var db = GetDb(DatabaseType.SqlServer);
91 | AddRecord(db);
92 | var pizza = db.Query("SELECT Id, OrderNumber FROM PizzaOrder WHERE Id=@Id", new
93 | {
94 | Id = PIZZA_ORDER_ID
95 | }).First();
96 | Assert.AreEqual(pizza.Id, PIZZA_ORDER_ID);
97 |
98 | var dynamic_pizza = db.Query("SELECT Id, OrderNumber FROM PizzaOrder WHERE Id=@Id", new
99 | {
100 | Id = PIZZA_ORDER_ID
101 | }).First();
102 | Assert.AreEqual(dynamic_pizza.Id, PIZZA_ORDER_ID);
103 | }
104 |
105 | private Database GetDb(DatabaseType databaseType)
106 | {
107 | var db = new Database();
108 | AppDomain.CurrentDomain.SetData("Assemblies", new string[] { "EntityFrameworkCore.BootKit.UnitTest" });
109 |
110 | if (databaseType == DatabaseType.Sqlite)
111 | {
112 | db.BindDbContext(new DatabaseBind
113 | {
114 | MasterConnection = new SqliteConnection($"Data Source={Directory.GetCurrentDirectory()}\\..\\..\\..\\..\\Bootkit.db"),
115 | CreateDbIfNotExist = true,
116 | });
117 | }
118 | else if (databaseType == DatabaseType.SqlServer)
119 | {
120 | db.BindDbContext(new DatabaseBind
121 | {
122 | MasterConnection = new SqlConnection("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Bootkit;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"),
123 | CreateDbIfNotExist = true
124 | });
125 | }
126 | else if (databaseType == DatabaseType.MySql)
127 | {
128 | db.BindDbContext(new DatabaseBind
129 | {
130 | MasterConnection = new MySqlConnection("Data Source=;port=3306;Initial Catalog=;user id=;password=;CharSet=utf8;Allow User Variables=True;"),
131 | CreateDbIfNotExist = false
132 | });
133 | }
134 | else if (databaseType == DatabaseType.MongoDb)
135 | {
136 | db.BindDbContext(new DatabaseBind
137 | {
138 | MasterConnection = new MongoDbConnection("mongodb://user:password@localhost:27017/db"),
139 | });
140 | }
141 | else if (databaseType == DatabaseType.PostgreSql)
142 | {
143 | db.BindDbContext(new DatabaseBind
144 | {
145 | MasterConnection = new NpgsqlConnection("Server=; Port=5439;User ID=;Password=;Database=;SSL Mode=Require;Trust Server Certificate=True;Use SSL Stream=True"),
146 | });
147 | }
148 | else if (databaseType == DatabaseType.Redshift)
149 | {
150 | db.BindDbContext(new DatabaseBind
151 | {
152 | MasterConnection = new NpgsqlConnection("Server=*.us-east-1.redshift.amazonaws.com; Port=5439;User ID=;Password=;Database=;Server Compatibility Mode=Redshift;SSL Mode=Require;Trust Server Certificate=True;Use SSL Stream=True"),
153 | });
154 | }
155 |
156 | return db;
157 | }
158 |
159 | private void GetRecordsByTableName(Database db)
160 | {
161 | var table = db.Table("PizzaOrder");
162 | var pizzaOrder = table.First(x => x.Id == PIZZA_ORDER_ID) as PizzaOrder;
163 | Assert.IsNotNull(pizzaOrder.Id);
164 | }
165 |
166 | public static String PIZZA_ORDER_ID = "7974f8d9-9124-4e24-a906-2e5bb3323e01";
167 |
168 | private void AddRecord(Database db)
169 | {
170 | var pizza = new PizzaOrder
171 | {
172 | Id = PIZZA_ORDER_ID,
173 | OrderNumber = new Random().Next(1000).ToString(),
174 | CustomerName = "Haiping Chen",
175 | CreatedTime = DateTime.UtcNow,
176 | PizzaTypes = new List {
177 | new PizzaType { Name = "Pizza Type 1", Amount = 10.99M },
178 | new PizzaType { Name = "Pizza Type 2", Amount = 9.9M }
179 | }
180 | };
181 |
182 | if (db.Table().Any(x => x.Id == PIZZA_ORDER_ID)) return;
183 |
184 | db.DbTran(() => db.Table().Add(pizza));
185 |
186 | var order = db.Table().Include(x => x.PizzaTypes).FirstOrDefault(x => x.Id == PIZZA_ORDER_ID);
187 |
188 | Assert.IsNotNull(order.Id);
189 | Assert.IsTrue(order.PizzaTypes.Count == 2);
190 | }
191 |
192 | private void UpdateRecordsByTableName(Database db)
193 | {
194 | DateTime dt = DateTime.UtcNow;
195 |
196 | var table = db.Table("PizzaOrder");
197 | var pizzaOrder = table.First(x => x.Id == PIZZA_ORDER_ID) as PizzaOrder;
198 | pizzaOrder.CreatedTime = dt;
199 |
200 | var po = db.Table().Find(PIZZA_ORDER_ID);
201 | Assert.IsTrue(po.CreatedTime == dt);
202 | }
203 |
204 | private void PatchRecord(Database db)
205 | {
206 | DateTime dt = DateTime.UtcNow.AddMinutes(-5);
207 |
208 | var patch = new DbPatchModel
209 | {
210 | Table = "PizzaOrder",
211 | Id = PIZZA_ORDER_ID
212 | };
213 |
214 | patch.Values.Add("CreatedTime", dt);
215 |
216 | int row = db.DbTran(() => db.Patch(patch));
217 |
218 | var po = db.Table().Find(PIZZA_ORDER_ID);
219 | Assert.IsTrue(po.CreatedTime.ToString() == dt.ToString());
220 | }
221 |
222 | private void AddRecordByTableName(Database db)
223 | {
224 | var entity = new PizzaType {
225 | Name = "PIZZA" + DateTime.UtcNow.Ticks,
226 | OrderId = PIZZA_ORDER_ID,
227 | Amount = new Random().Next(10000)
228 | };
229 |
230 | db.Add("PizzaType", entity);
231 |
232 | Assert.IsNotNull(entity.Id);
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/EntityFrameworkCore.BootKit/Database.cs:
--------------------------------------------------------------------------------
1 | using Dapper;
2 | using EntityFrameworkCore.BootKit.Models;
3 | using Microsoft.EntityFrameworkCore;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Data;
7 | using System.Data.Common;
8 | using System.Linq;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace EntityFrameworkCore.BootKit;
13 |
14 | public class Database
15 | {
16 | public List DbContextBinds;
17 |
18 | public Database()
19 | {
20 | DbContextBinds = new List();
21 | }
22 |
23 | public DatabaseBind GetBinding(Type tableInterface)
24 | {
25 | var binding = DbContextBinds.FirstOrDefault(x => (x.TableInterface != null && x.TableInterface.Equals(tableInterface)) ||
26 | (x.Entities != null && x.Entities.Select(e => e.Name).Contains(tableInterface.Name)));
27 |
28 | if (binding == null)
29 | {
30 | throw new Exception($"Can't find binding for interface {tableInterface.ToString()}");
31 | }
32 |
33 | return binding;
34 | }
35 |
36 | public DatabaseBind GetBinding(string tableName)
37 | {
38 | var binding = DbContextBinds.FirstOrDefault(x => x.Entities != null && x.Entities.Select(entity => entity.Name.ToLower()).Contains(tableName.ToLower()));
39 |
40 | if (binding == null)
41 | {
42 | throw new Exception($"Can't find binding for table {tableName}");
43 | }
44 |
45 | return binding;
46 | }
47 |
48 | private List GetAllEntityTypes(DatabaseBind bind)
49 | {
50 | var assemblies = (string[])AppDomain.CurrentDomain.GetData("Assemblies");
51 | return Utility.GetClassesWithInterface(bind.TableInterface, assemblies);
52 | }
53 |
54 | public void BindDbContext(DatabaseBind bind)
55 | {
56 | bind.Entities = GetAllEntityTypes(bind).ToList();
57 |
58 | DbContextBinds.Add(bind);
59 | }
60 |
61 | public void BindDbContext(DatabaseBind bind)
62 | {
63 | bind.TableInterface = typeof(TTableInterface);
64 | bind.DbContextType = typeof(TDbContextType);
65 |
66 | bind.Entities = GetAllEntityTypes(bind).ToList();
67 |
68 | if (bind.SlaveConnections == null)
69 | bind.SlaveConnections = new List();
70 |
71 | if (bind.SlaveConnections.Count == 0)
72 | bind.SlaveConnections.Add(bind.MasterConnection);
73 |
74 | // random
75 | bind.SlaveId = new Random().Next(bind.SlaveConnections.Count);
76 |
77 | DbContextBinds.Add(bind);
78 |
79 | if (bind.CreateDbIfNotExist)
80 | GetMaster(bind.TableInterface).Database.EnsureCreated();
81 | }
82 |
83 | public DataContext GetMaster(Type tableInterface)
84 | {
85 | var binding = GetBinding(tableInterface);
86 |
87 | if (binding.DbContextMaster == null)
88 | {
89 | DbContextOptions options = new DbContextOptions();
90 | DataContext dbContext = Activator.CreateInstance(binding.DbContextType, options, binding.ServiceProvider) as DataContext;
91 | dbContext.ConnectionString = binding.MasterConnection.ConnectionString;
92 | dbContext.EntityTypes = binding.Entities;
93 | binding.DbContextMaster = dbContext;
94 | }
95 |
96 | return binding.DbContextMaster;
97 | }
98 |
99 | public DataContext GetReader(Type tableInterface)
100 | {
101 | var binding = GetBinding(tableInterface);
102 |
103 | if (binding.DbContextSlaver == null)
104 | {
105 | DbContextOptions options = new DbContextOptions();
106 |
107 | DataContext dbContext = Activator.CreateInstance(binding.DbContextType, options, binding.ServiceProvider) as DataContext;
108 | dbContext.EntityTypes = binding.Entities;
109 |
110 | if (binding.SlaveConnections == null || binding.SlaveConnections.Count == 0)
111 | dbContext.ConnectionString = binding.MasterConnection.ConnectionString;
112 | else
113 | dbContext.ConnectionString = binding.SlaveConnection.ConnectionString;
114 |
115 | binding.DbContextSlaver = dbContext;
116 | }
117 |
118 | return binding.DbContextSlaver;
119 | }
120 |
121 | private string RandomConn(List connetions)
122 | {
123 | int idx = new Random().Next(connetions.Count);
124 | return connetions[idx].ConnectionString;
125 | }
126 |
127 | /*public IMongoCollection Collection(string collection) where T : class
128 | {
129 | DatabaseBind binding = GetBinding(typeof(T));
130 | if (binding.DbContextMaster == null)
131 | {
132 | binding.DbContext = new MongoDbContext(binding.ConnectionString);
133 | }
134 |
135 | return binding.DbContextSlavers.First();
136 | }*/
137 |
138 | public Object Find(Type type, params string[] keys)
139 | {
140 | DatabaseBind binding = DbContextBinds.First(x => x.Entities.Contains(type));
141 | if (binding.DbContextMaster == null || binding.DbContextMaster.Database.CurrentTransaction == null)
142 | {
143 | return GetReader(type).Find(type, keys);
144 | }
145 | else
146 | {
147 | return GetMaster(type).Find(type, keys);
148 | }
149 | }
150 |
151 | public void Add(object entity)
152 | {
153 | var db = GetMaster(typeof(TTableInterface));
154 | db.Add(entity);
155 | }
156 |
157 | public void Add(IEnumerable