ow
This commit is contained in:
1 parent
31fbe199c1
commit
1c0c83af5f
469 files changed
+62544
-5
No files matched your search
@@ -0,0 +1,58 @@
|
||||
using CloudBuilder.Core.Application.Builders;
|
||||
using CloudBuilder.Core.DatabaseAccessor.Entity;
|
||||
using CloudBuilder.Core.Policy;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor
|
||||
{
|
||||
public class ApplicationService : IApplicationService
|
||||
{
|
||||
|
||||
public ApplicationService(
|
||||
CloudBuilderBuilder cloudBuilder,
|
||||
IConfiguration configuration,
|
||||
IServiceProvider serviceProvider,
|
||||
IUnitOfWork unitOfWork,
|
||||
IHttpContextAccessor httpContext
|
||||
)
|
||||
{
|
||||
CloudBuilder = cloudBuilder;
|
||||
this.Configuration = configuration;
|
||||
this.ServiceProvider = serviceProvider;
|
||||
this.UnitOfWork = unitOfWork;
|
||||
this.HttpContext = httpContext;
|
||||
if (httpContext.HttpContext != null)
|
||||
{
|
||||
UserId = ClaimPolicy.GetClaimValue(HttpContext, ClaimPolicy.CLAINM_USERID);
|
||||
string key = ClaimPolicy.GetHeaderKeyValue(HttpContext, ClaimPolicy.HEADER_LOCALE);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
Locale = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IServiceProvider ServiceProvider { get; private set; }
|
||||
|
||||
public IHttpContextAccessor HttpContext { get; private set; }
|
||||
|
||||
public string UserId { get; set; }
|
||||
public string Locale { get; set; } = ClaimPolicy.CLAINM_LOCALE;
|
||||
public IUnitOfWork UnitOfWork { get; set; }
|
||||
public CloudBuilderBuilder CloudBuilder { get; set; }
|
||||
public IConfiguration Configuration { get; private set; }
|
||||
|
||||
public KRepository GetRepository<KRepository>()
|
||||
{
|
||||
return ServiceProvider.GetRequiredService<KRepository>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示数据库类型,如SqlServer,Sqlite等
|
||||
/// </summary>
|
||||
public enum DatabaseType
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlServer数据库类型
|
||||
/// </summary>
|
||||
SqlServer,
|
||||
/// <summary>
|
||||
/// Sqlite数据库类型
|
||||
/// </summary>
|
||||
Sqlite,
|
||||
/// <summary>
|
||||
/// MySql数据库类型
|
||||
/// </summary>
|
||||
MySql,
|
||||
/// <summary>
|
||||
/// PostgreSql数据库类型
|
||||
/// </summary>
|
||||
PostgreSql,
|
||||
/// <summary>
|
||||
/// Oracle数据库类型
|
||||
/// </summary>
|
||||
Oracle
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体类基类
|
||||
/// </summary>
|
||||
public abstract class EntityBase<TKey> : IEntity<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置 编号
|
||||
/// </summary>
|
||||
[DisplayName("编号")]
|
||||
[NotMapped]
|
||||
public TKey? Id { get; set; }
|
||||
|
||||
public virtual string GetSelectFrom()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual string GetSelectCountFrom(string sqlWhere)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual string GetSelectTopFrom(int limit, int start, string orderby, string orderbytag, string sqlWhere)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断两个实体是否是同一数据记录的实体
|
||||
/// </summary>
|
||||
/// <param name="obj">要比较的实体信息</param>
|
||||
/// <returns></returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(obj is EntityBase<TKey> entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return IsKeyEqual(entity.Id, Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实体ID是否相等
|
||||
/// </summary>
|
||||
public static bool IsKeyEqual(TKey id1, TKey id2)
|
||||
{
|
||||
if (id1 == null && id2 == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (id1 == null || id2 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals(id1, id2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用作特定类型的哈希函数。
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// 当前 <see cref="T:System.Object"/> 的哈希代码。<br/>
|
||||
/// 如果<c>Id</c>为<c>null</c>则返回0,
|
||||
/// 如果不为<c>null</c>则返回<c>Id</c>对应的哈希值
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
if (Id == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return Id.ToString().GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using CloudBuilder.Core.Application.Builders;
|
||||
using CloudBuilder.Core.Policy;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
public interface IApplicationService
|
||||
{
|
||||
CloudBuilderBuilder CloudBuilder { get; set; }
|
||||
IConfiguration Configuration { get; }
|
||||
/// <summary>
|
||||
/// 服务提供器
|
||||
/// </summary>
|
||||
IServiceProvider ServiceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录ID
|
||||
/// </summary>
|
||||
string UserId { get; set; }
|
||||
string Locale { get; set; }
|
||||
/// <summary>
|
||||
/// 事务
|
||||
/// </summary>
|
||||
IUnitOfWork UnitOfWork { get; set; }
|
||||
/// <summary>
|
||||
/// 数据仓库
|
||||
/// </summary>
|
||||
/// <typeparam name="K"></typeparam>
|
||||
/// <returns></returns>
|
||||
K GetRepository<K>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据模型接口
|
||||
/// </summary>
|
||||
public interface IEntity<TKey> : IGet
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置 实体唯一标识,主键
|
||||
/// </summary>
|
||||
TKey Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
public interface IEntityAudited
|
||||
{
|
||||
public const string CREATED_DATETIME = "CreatedDatetime";
|
||||
public const string CREATED_BY = "CreatedBy";
|
||||
public const string UPDATED_DATETIME = "UpdatedDatetime";
|
||||
public const string UPDATED_BY = "UpdatedBy";
|
||||
public const string ROW_VERSION = "RowVersion";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
public interface IGet
|
||||
{
|
||||
string GetSelectFrom();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册主库实体类
|
||||
/// </summary>
|
||||
public interface IMaster
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 定义实体仓储模型的数据标准操作
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">实体类型</typeparam>
|
||||
/// <typeparam name="TKey">主键类型</typeparam>
|
||||
public interface IRepository<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体集合
|
||||
/// </summary>
|
||||
DbSet<TEntity> Entities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 不跟踪的(脱轨)实体
|
||||
/// </summary>
|
||||
IQueryable<TEntity> DetachedEntities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务提供器
|
||||
/// </summary>
|
||||
IServiceProvider ServiceProvider { get; }
|
||||
/// <summary>
|
||||
/// 事务
|
||||
/// </summary>
|
||||
IUnitOfWork UnitOfWork { get; set; }
|
||||
|
||||
DbContext GetDbContext();
|
||||
|
||||
K GetRepository<K>();
|
||||
/// <summary>
|
||||
/// 动态改变主数据库
|
||||
/// </summary>
|
||||
void ChangeMasterDatabase();
|
||||
|
||||
/// <summary>
|
||||
/// 动态改变主数据库
|
||||
/// </summary>
|
||||
void ChangeSecondaryDatabase();
|
||||
|
||||
#region FromSqlRaw
|
||||
IQueryable<TEntity> FromSql(string sql, params object[] parameters);
|
||||
IQueryable<TEntity> FromSqlWhere(TEntity t, string where, params object[] parameters);
|
||||
|
||||
TEntity[] FindBySql(string sql, params object[] parameters);
|
||||
TEntity[] FindBySqlWhere(TEntity t, string where, params object[] parameters);
|
||||
|
||||
void PackSqlParameter(List<object> parameters, string parameterName, object value);
|
||||
|
||||
void ExecuteNonQuery(string sql, params object[] parameters);
|
||||
|
||||
object ExecuteScalar(string sql, params object[] parameters);
|
||||
|
||||
DataTable SelectDataTable(string sql, params object[] parameters);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Insert
|
||||
|
||||
EntityEntry<TEntity> Insert(TEntity entity);
|
||||
|
||||
void Insert(params TEntity[] entities);
|
||||
|
||||
void Insert(IEnumerable<TEntity> entities);
|
||||
|
||||
Task<EntityEntry<TEntity>> InsertAsync(TEntity entity, CancellationToken cancellationToken = default);
|
||||
|
||||
Task InsertAsync(params TEntity[] entities);
|
||||
|
||||
Task InsertAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);
|
||||
|
||||
EntityEntry<TEntity> InsertNow(TEntity entity);
|
||||
|
||||
void InsertNow(params TEntity[] entities);
|
||||
|
||||
void InsertNow(IEnumerable<TEntity> entities);
|
||||
|
||||
Task<EntityEntry<TEntity>> InsertNowAsync(TEntity entity, CancellationToken cancellationToken = default);
|
||||
|
||||
Task InsertNowAsync(params TEntity[] entities);
|
||||
|
||||
Task InsertNowAsync(TEntity[] entities, CancellationToken cancellationToken = default);
|
||||
|
||||
Task InsertNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);
|
||||
int SaveNow();
|
||||
|
||||
Task<int> SaveNowAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update
|
||||
EntityEntry<TEntity> Update(TEntity entity);
|
||||
void Update(params TEntity[] entities);
|
||||
void Update(IEnumerable<TEntity> entities);
|
||||
Task<EntityEntry<TEntity>> UpdateAsync(TEntity entity);
|
||||
Task UpdateAsync(params TEntity[] entities);
|
||||
Task UpdateAsync(IEnumerable<TEntity> entities);
|
||||
EntityEntry<TEntity> UpdateNow(TEntity entity);
|
||||
void UpdateNow(params TEntity[] entities);
|
||||
void UpdateNow(IEnumerable<TEntity> entities);
|
||||
Task<EntityEntry<TEntity>> UpdateNowAsync(TEntity entity, CancellationToken cancellationToken = default);
|
||||
Task UpdateNowAsync(params TEntity[] entities);
|
||||
Task UpdateNowAsync(TEntity[] entities, CancellationToken cancellationToken = default);
|
||||
Task UpdateNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);
|
||||
EntityEntry<TEntity> UpdateInclude(TEntity entity, IEnumerable<string> propertyNames);
|
||||
EntityEntry<TEntity> UpdateInclude(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, string[] propertyNames);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, IEnumerable<string> propertyNames);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
|
||||
EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, string[] propertyNames);
|
||||
EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
|
||||
EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, IEnumerable<string> propertyNames);
|
||||
EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates, CancellationToken cancellationToken = default);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, IEnumerable<string> propertyNames, CancellationToken cancellationToken = default);
|
||||
Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates, CancellationToken cancellationToken = default);
|
||||
EntityEntry<TEntity> UpdateExclude(TEntity entity, IEnumerable<string> propertyNames);
|
||||
EntityEntry<TEntity> UpdateExclude(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, string[] propertyNames);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, IEnumerable<string> propertyNames);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
|
||||
EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, string[] propertyNames);
|
||||
EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
|
||||
EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, IEnumerable<string> propertyNames);
|
||||
EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates, CancellationToken cancellationToken = default);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, IEnumerable<string> propertyNames, CancellationToken cancellationToken = default);
|
||||
Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates, CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete
|
||||
EntityEntry<TEntity> Delete(TEntity entity);
|
||||
void Delete(params TEntity[] entities);
|
||||
void Delete(IEnumerable<TEntity> entities);
|
||||
Task<EntityEntry<TEntity>> DeleteAsync(TEntity entity);
|
||||
Task DeleteAsync(params TEntity[] entities);
|
||||
Task DeleteAsync(IEnumerable<TEntity> entities);
|
||||
EntityEntry<TEntity> DeleteNow(TEntity entity);
|
||||
void DeleteNow(params TEntity[] entities);
|
||||
void DeleteNow(IEnumerable<TEntity> entities);
|
||||
Task<EntityEntry<TEntity>> DeleteNowAsync(TEntity entity, CancellationToken cancellationToken = default);
|
||||
Task DeleteNowAsync(params TEntity[] entities);
|
||||
Task DeleteNowAsync(TEntity[] entities, CancellationToken cancellationToken = default);
|
||||
Task DeleteNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 注入从库实体类
|
||||
/// </summary>
|
||||
public interface ISecondary
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 实现接口将生成TypeScript文件的条件
|
||||
/// </summary>
|
||||
public interface IData
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 业务单元操作接口
|
||||
/// </summary>
|
||||
public interface IUnitOfWork : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取 工作单元的事务是否已提交
|
||||
/// </summary>
|
||||
bool HasCommitted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加DbContext共享事务
|
||||
/// </summary>
|
||||
void AddDbContext(DbContext dbContext);
|
||||
/// <summary>
|
||||
/// 获取指定数据实体的上下文类型
|
||||
/// </summary>
|
||||
/// <param name="entityType">实体类型</param>
|
||||
/// <returns>实体所属上下文实例</returns>
|
||||
DbContext GetDbContext();
|
||||
|
||||
/// <summary>
|
||||
/// 对数据库连接开启事务
|
||||
/// </summary>
|
||||
void BeginOrUseTransaction();
|
||||
|
||||
/// <summary>
|
||||
/// 对数据库连接开启事务
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">异步取消标记</param>
|
||||
/// <returns></returns>
|
||||
Task BeginOrUseTransactionAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 提交当前上下文的事务更改
|
||||
/// </summary>
|
||||
void Commit();
|
||||
|
||||
/// <summary>
|
||||
/// 回滚所有事务
|
||||
/// </summary>
|
||||
void Rollback();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
public abstract class ViewEntityBase : IEntity<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// View没有主键
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public string? Id { get; set; }
|
||||
|
||||
public virtual string GetSelectFrom()
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
public virtual string GetSelectCountFrom(string sqlWhere)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
public virtual string GetSelectTopFrom(int limit, int start, string orderby, string orderbytag, string sqlWhere)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
using CloudBuilder.Core.DatabaseAccessor.Entity;
|
||||
using CloudBuilder.Core.DependencyInjection.EFCore;
|
||||
using CloudBuilder.Core.Policy;
|
||||
using CloudBuilder.Core.Service;
|
||||
using DocumentFormat.OpenXml.Math;
|
||||
using DocumentFormat.OpenXml.Vml.Office;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor
|
||||
{
|
||||
public class MasterDbContext : DbContext
|
||||
{
|
||||
public const string MASTER_DB_CONTEXT = "MasterDbContext";
|
||||
|
||||
public IEnumerable<IMasterRegistEntityType<ModelBuilder>> _entityManagers;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IConfiguration configuration;
|
||||
private readonly IHttpContextAccessor httpContextAccessor;
|
||||
|
||||
public MasterDbContext(DbContextOptions<MasterDbContext> options,
|
||||
IEnumerable<IMasterRegistEntityType<ModelBuilder>> entityManagers,
|
||||
IServiceProvider serviceProvider,
|
||||
IConfiguration configuration,
|
||||
IHttpContextAccessor httpContextAccessor
|
||||
) : base(options)
|
||||
{
|
||||
_entityManagers = entityManagers;
|
||||
_serviceProvider = serviceProvider;
|
||||
this.configuration = configuration;
|
||||
this.httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
SavingChangesEvent();
|
||||
return base.SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//自动检验数据是否过时
|
||||
//ALTER TABLE table ADD row_version rowversion;
|
||||
//[Column("row_version")]
|
||||
//[Timestamp]
|
||||
//public byte[] RowVersion { get; set; }
|
||||
if (ex.Message.Contains("data may have been modified or deleted since entities were loaded."))
|
||||
{
|
||||
throw new ValidatedException(CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.THE_DATA_HAS_BEEN_MODIFIED));
|
||||
}
|
||||
throw new ValidatedException(ex.InnerException?.Message ?? ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SavingChangesEvent()
|
||||
{
|
||||
var entities = this.ChangeTracker.Entries()
|
||||
.Where(u => (u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added)).ToList();
|
||||
if (entities == null || entities.Count < 1) return;
|
||||
|
||||
string uid = this.httpContextAccessor.HttpContext?.User?.Identity?.Name;
|
||||
|
||||
DateTime now = DateTime.Now;
|
||||
if (string.IsNullOrEmpty(uid))
|
||||
{
|
||||
uid = GetUserIdFromToken(httpContextAccessor.HttpContext!);
|
||||
}
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (!(entity.State == EntityState.Added || entity.State == EntityState.Modified)) continue;
|
||||
|
||||
// 获取所有实体有效属性,排除 [NotMapper] 属性
|
||||
var props = entity.OriginalValues.Properties;
|
||||
|
||||
// 获取实体当前(现在)的值
|
||||
var currentValues = entity.CurrentValues;
|
||||
|
||||
// 遍历所有属性
|
||||
foreach (var prop in props)
|
||||
{
|
||||
// 获取属性名
|
||||
var propName = prop.Name;
|
||||
if (propName == IEntityAudited.CREATED_BY && entity.State == EntityState.Added)
|
||||
{
|
||||
currentValues[propName] = uid;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName == IEntityAudited.CREATED_DATETIME && entity.State == EntityState.Added)
|
||||
{
|
||||
currentValues[propName] = DateTime.Now;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName == IEntityAudited.UPDATED_BY)
|
||||
{
|
||||
currentValues[propName] = uid;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName == IEntityAudited.UPDATED_DATETIME)
|
||||
{
|
||||
currentValues[propName] = DateTime.Now;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
var entityName = entity.Metadata.GetTableName() ?? entity.Entity.GetType().Name;
|
||||
var state = entity.State;
|
||||
|
||||
// ======================================
|
||||
// 1. 获取所有主键(支持复合主键)
|
||||
// ======================================
|
||||
var pkProps = entity.Properties
|
||||
.Where(p => p.Metadata.IsPrimaryKey())
|
||||
.ToList();
|
||||
|
||||
// 拼接 WHERE 条件:Id=1 AND TenantId=2
|
||||
var whereClauses = pkProps
|
||||
.Select(p => $"{p.Metadata.GetColumnName()?? p.Metadata.Name} = '{p.CurrentValue?.ToString()?.Replace("'", "''")}'");
|
||||
string whereSql = string.Join(" AND ", whereClauses);
|
||||
|
||||
string sqlLog = "";
|
||||
|
||||
// ======================================
|
||||
// 修改 UPDATE
|
||||
// ======================================
|
||||
if (state == EntityState.Modified)
|
||||
{
|
||||
var setClauses = entity.Properties
|
||||
.Where(p => p.IsModified) // 只记录真正修改的字段
|
||||
.Select(p => $"{p.Metadata.GetColumnName() ?? p.Metadata.Name} = '{p.CurrentValue?.ToString()?.Replace("'", "''")}'");
|
||||
|
||||
string setSql = string.Join(", ", setClauses);
|
||||
sqlLog = $"[{uid}][{now.ToString("yyyy-MM-dd HH:mm:ss")}]UPDATE {entityName} SET {setSql} WHERE {whereSql}";
|
||||
}
|
||||
|
||||
// ======================================
|
||||
// 新增 INSERT
|
||||
// ======================================
|
||||
else if (state == EntityState.Added)
|
||||
{
|
||||
var data = entity.Properties.ToDictionary(p => p.Metadata.GetColumnName() ?? p.Metadata.Name, p => p.CurrentValue);
|
||||
var columns = string.Join(", ", data.Keys);
|
||||
var values = string.Join(", ", data.Values.Select(v => $"'{v?.ToString()?.Replace("'", "''")}'"));
|
||||
sqlLog = $"[{uid}][{now.ToString("yyyy-MM-dd HH:mm:ss")}]INSERT INTO {entityName} ({columns}) VALUES ({values})";
|
||||
}
|
||||
|
||||
// ======================================
|
||||
// 删除 DELETE
|
||||
// ======================================
|
||||
else if (state == EntityState.Deleted)
|
||||
{
|
||||
sqlLog = $"[{uid}][{now.ToString("yyyy-MM-dd HH:mm:ss")}]DELETE FROM {entityName} WHERE {whereSql}";
|
||||
}
|
||||
|
||||
WriteToFile(sqlLog);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteToFile(string log)
|
||||
{
|
||||
try
|
||||
{
|
||||
long MaxFileSizeBytes = (long)(configuration.GetValue<int>("Logging:MaxFileSizeMB") * 1024 * 1024);
|
||||
|
||||
string today = DateTime.Now.ToString("yyyyMMdd");
|
||||
string basePath = configuration["Logging:LogFileDirectory"];
|
||||
Directory.CreateDirectory(basePath);
|
||||
|
||||
string baseFileName = $"log-{today}";
|
||||
string ext = ".log";
|
||||
string finalPath = Path.Combine(basePath, $"{baseFileName}{ext}");
|
||||
int index = 1;
|
||||
|
||||
// 循环找没超过大小的文件
|
||||
while (File.Exists(finalPath) && new FileInfo(finalPath).Length >= MaxFileSizeBytes)
|
||||
{
|
||||
finalPath = Path.Combine(basePath, $"{baseFileName}-{index}{ext}");
|
||||
index++;
|
||||
}
|
||||
|
||||
// 写入(线程安全)
|
||||
lock (this)
|
||||
{
|
||||
File.AppendAllText(finalPath, log + Environment.NewLine, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
foreach (IMasterRegistEntityType<ModelBuilder> entityManager in _entityManagers)
|
||||
{
|
||||
entityManager.RegistEntity(builder);
|
||||
}
|
||||
|
||||
base.OnModelCreating(builder);
|
||||
}
|
||||
|
||||
public string GetJwtBearerToken(HttpContext httpContext, string headerKey = "Authorization", string tokenPrefix = "Bearer ")
|
||||
{
|
||||
if (httpContext == null) return null;
|
||||
// 判断请求报文头中是否有 "Authorization" 报文头
|
||||
var bearerToken = httpContext.Request.Headers[headerKey].ToString();
|
||||
if (string.IsNullOrWhiteSpace(bearerToken)) return default;
|
||||
|
||||
var prefixLenght = tokenPrefix.Length;
|
||||
return bearerToken.StartsWith(tokenPrefix, true, null) && bearerToken.Length > prefixLenght ? bearerToken[prefixLenght..] : default;
|
||||
}
|
||||
|
||||
public string GetUserIdFromToken(HttpContext httpContext)
|
||||
{
|
||||
string token = GetJwtBearerToken(httpContextAccessor.HttpContext!);
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonWebToken json = new JsonWebTokenHandler().ReadJsonWebToken(token);
|
||||
return json.GetClaim(ClaimPolicy.CLAINM_USERID).Value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,893 @@
|
||||
using CloudBuilder.Core.Application.Builders;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor.Entity
|
||||
{
|
||||
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
|
||||
{
|
||||
private readonly CloudBuilderBuilder builder;
|
||||
private DbContext dbContext;
|
||||
private readonly IHttpContextAccessor httpContext;
|
||||
|
||||
public Repository(IServiceProvider serviceProvider,
|
||||
[FromKeyedServices(MasterDbContext.MASTER_DB_CONTEXT)] DbContext dbContext,
|
||||
IUnitOfWork unitOfWork,
|
||||
IHttpContextAccessor httpContext)
|
||||
{
|
||||
this.httpContext = httpContext;
|
||||
this.dbContext = dbContext;
|
||||
this.UnitOfWork = unitOfWork;
|
||||
ServiceProvider = serviceProvider;
|
||||
Entities = this.dbContext.Set<TEntity>()!;
|
||||
DetachedEntities = Entities.AsNoTracking()!;
|
||||
}
|
||||
|
||||
public IUnitOfWork UnitOfWork { get; set; }
|
||||
|
||||
public DbContext GetDbContext() { return dbContext; }
|
||||
|
||||
public DbSet<TEntity> Entities { get; set; } = null!;
|
||||
|
||||
public IQueryable<TEntity> DetachedEntities { get; set; } = null!;
|
||||
|
||||
|
||||
public DbConnection DbConnection
|
||||
{
|
||||
get
|
||||
{
|
||||
return dbContext.Database.GetDbConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public IServiceProvider ServiceProvider { get; set; } = null!;
|
||||
|
||||
public virtual TRepository GetRepository<TRepository>()
|
||||
{
|
||||
return ServiceProvider.GetRequiredService<TRepository>();
|
||||
}
|
||||
|
||||
public void ChangeMasterDatabase()
|
||||
{
|
||||
this.dbContext = ServiceProvider.GetRequiredKeyedService<DbContext>(MasterDbContext.MASTER_DB_CONTEXT);
|
||||
Entities = this.dbContext.Set<TEntity>()!;
|
||||
DetachedEntities = Entities.AsNoTracking()!;
|
||||
}
|
||||
|
||||
public void ChangeSecondaryDatabase()
|
||||
{
|
||||
this.dbContext = ServiceProvider.GetRequiredKeyedService<DbContext>(SecondaryDbContext.SECONDARY_DB_CONTEXT);
|
||||
Entities = this.dbContext.Set<TEntity>()!;
|
||||
DetachedEntities = Entities.AsNoTracking()!;
|
||||
}
|
||||
|
||||
#region FromSqlRaw
|
||||
|
||||
public virtual IQueryable<TEntity> FromSql(string sql, params object[] parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
return Entities.FromSqlRaw(sql);
|
||||
else
|
||||
return Entities.FromSqlRaw(sql, parameters);
|
||||
}
|
||||
|
||||
public virtual IQueryable<TEntity> FromSqlWhere(TEntity t, string where, params object[] parameters)
|
||||
{
|
||||
string sql = $"{((IEntity<object>)t).GetSelectFrom()} {where} ";
|
||||
if (parameters == null)
|
||||
return Entities.FromSqlRaw(sql);
|
||||
else
|
||||
return Entities.FromSqlRaw(sql, parameters);
|
||||
}
|
||||
|
||||
public virtual TEntity[] FindBySql(string sql, params object[] parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
return Entities.FromSqlRaw(sql).ToArray();
|
||||
else
|
||||
return Entities.FromSqlRaw(sql, parameters).ToArray();
|
||||
}
|
||||
|
||||
public virtual TEntity[] FindBySqlWhere(TEntity t, string where, params object[] parameters)
|
||||
{
|
||||
string sql = $"{((IGet)t).GetSelectFrom()} {where} ";
|
||||
if (parameters == null)
|
||||
return Entities.FromSqlRaw(sql).ToArray();
|
||||
else
|
||||
return Entities.FromSqlRaw(sql, parameters).ToArray();
|
||||
}
|
||||
|
||||
public void PackSqlParameter(List<object> parameters, string parameterName, object value)
|
||||
{
|
||||
if (parameters == null) parameters = new List<object>();
|
||||
else
|
||||
{
|
||||
string formatedValue;
|
||||
if (value == null) formatedValue = $"null";
|
||||
else
|
||||
{
|
||||
formatedValue = $"'{value.ToString()}'";
|
||||
if (value is DateTime && !string.IsNullOrEmpty(formatedValue))
|
||||
formatedValue = $"'{Convert.ToDateTime(formatedValue).ToString("yyyy-MM-dd HH:mm:ss")}'";
|
||||
}
|
||||
|
||||
parameters.Add(new SqlParameter(parameterName, value == null ? DBNull.Value : value));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ExecuteNonQuery(string sql, params object[] parameters)
|
||||
{
|
||||
var conn = dbContext.Database.GetDbConnection(); ;
|
||||
|
||||
conn.Open();
|
||||
var cmd = conn.CreateCommand();
|
||||
|
||||
cmd.CommandText = sql;
|
||||
if (parameters != null && parameters.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
public virtual object ExecuteScalar(string sql, params object[] parameters)
|
||||
{
|
||||
var conn = dbContext.Database.GetDbConnection(); ;
|
||||
|
||||
conn.Open();
|
||||
var cmd = conn.CreateCommand();
|
||||
|
||||
cmd.CommandText = sql;
|
||||
if (parameters != null && parameters.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
|
||||
|
||||
return cmd.ExecuteScalar();
|
||||
}
|
||||
|
||||
public virtual DataTable SelectDataTable(string sql, params object[] parameters)
|
||||
{
|
||||
var conn = dbContext.Database.GetDbConnection(); ;
|
||||
|
||||
conn.Open();
|
||||
var cmd = conn.CreateCommand();
|
||||
|
||||
cmd.CommandText = sql;
|
||||
if (parameters != null && parameters.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
|
||||
SqlDataAdapter da = new SqlDataAdapter();
|
||||
da.SelectCommand = cmd as SqlCommand;
|
||||
DataTable dt = new DataTable();
|
||||
da.Fill(dt);
|
||||
|
||||
dt.TableName = "TableName";
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Insert
|
||||
|
||||
public virtual EntityEntry<TEntity> Insert(TEntity entity)
|
||||
{
|
||||
var entryEntity = Entities.Add(entity);
|
||||
|
||||
return entryEntity;
|
||||
}
|
||||
|
||||
public virtual void Insert(params TEntity[] entities)
|
||||
{
|
||||
Entities.AddRange(entities);
|
||||
}
|
||||
|
||||
public virtual void Insert(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Entities.AddRange(entities);
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await Entities.AddAsync(entity, cancellationToken);
|
||||
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual Task InsertAsync(params TEntity[] entities)
|
||||
{
|
||||
return Entities.AddRangeAsync(entities);
|
||||
}
|
||||
|
||||
public virtual Task InsertAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Entities.AddRangeAsync(entities, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> InsertNow(TEntity entity)
|
||||
{
|
||||
var entityEntry = Insert(entity);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增多条记录
|
||||
/// </summary>
|
||||
/// <param name="entities">多个实体</param>
|
||||
public virtual void InsertNow(params TEntity[] entities)
|
||||
{
|
||||
Insert(entities);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增多条记录
|
||||
/// </summary>
|
||||
/// <param name="entities">多个实体</param>
|
||||
public virtual void InsertNow(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Insert(entities);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增一条记录并立即提交
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <param name="ignoreNullValues"></param>
|
||||
/// <param name="cancellationToken">取消异步令牌</param>
|
||||
/// <returns>数据库中返回的实体</returns>
|
||||
public virtual async Task<EntityEntry<TEntity>> InsertNowAsync(TEntity entity, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await InsertAsync(entity, cancellationToken);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增多条记录并立即提交
|
||||
/// </summary>
|
||||
/// <param name="entities">多个实体</param>
|
||||
/// <returns>Task</returns>
|
||||
public virtual async Task InsertNowAsync(params TEntity[] entities)
|
||||
{
|
||||
await InsertAsync(entities);
|
||||
await SaveNowAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增多条记录并立即提交
|
||||
/// </summary>
|
||||
/// <param name="entities">多个实体</param>
|
||||
/// <param name="cancellationToken">取消异步令牌</param>
|
||||
/// <returns>Task</returns>
|
||||
public virtual async Task InsertNowAsync(TEntity[] entities, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await InsertAsync(entities);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增多条记录并立即提交
|
||||
/// </summary>
|
||||
/// <param name="entities">多个实体</param>
|
||||
/// <param name="cancellationToken">取消异步令牌</param>
|
||||
/// <returns>Task</returns>
|
||||
public virtual async Task InsertNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await InsertAsync(entities, cancellationToken);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 提交更改操作
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual int SaveNow()
|
||||
{
|
||||
return dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提交更改操作(异步)
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task<int> SaveNowAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update
|
||||
public virtual EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var entityEntry = Entities.Update(entity);
|
||||
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual void Update(params TEntity[] entities)
|
||||
{
|
||||
Entities.UpdateRange(entities);
|
||||
}
|
||||
|
||||
public virtual void Update(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Entities.UpdateRange(entities);
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateAsync(TEntity entity)
|
||||
{
|
||||
return Task.FromResult(Update(entity));
|
||||
}
|
||||
|
||||
public virtual Task UpdateAsync(params TEntity[] entities)
|
||||
{
|
||||
Update(entities);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task UpdateAsync(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Update(entities);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateNow(TEntity entity)
|
||||
{
|
||||
var entityEntry = Update(entity);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual void UpdateNow(params TEntity[] entities)
|
||||
{
|
||||
Update(entities);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public virtual void UpdateNow(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Update(entities);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateNowAsync(TEntity entity, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateAsync(entity);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task UpdateNowAsync(params TEntity[] entities)
|
||||
{
|
||||
await UpdateAsync(entities);
|
||||
await SaveNowAsync();
|
||||
}
|
||||
|
||||
public virtual async Task UpdateNowAsync(TEntity[] entities, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await UpdateAsync(entities);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task UpdateNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await UpdateAsync(entities);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateInclude(TEntity entity, IEnumerable<string> propertyNames)
|
||||
{
|
||||
var entityEntry = ChangeEntityState(entity, EntityState.Detached);
|
||||
foreach (var propertyName in propertyNames)
|
||||
{
|
||||
EntityPropertyEntry(entity, propertyName).IsModified = true;
|
||||
}
|
||||
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateInclude(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates)
|
||||
{
|
||||
var entityEntry = ChangeEntityState(entity, EntityState.Detached);
|
||||
foreach (var propertyPredicate in propertyPredicates)
|
||||
{
|
||||
EntityPropertyEntry(entity, propertyPredicate).IsModified = true;
|
||||
}
|
||||
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, string[] propertyNames)
|
||||
{
|
||||
return Task.FromResult(UpdateInclude(entity, propertyNames));
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates)
|
||||
{
|
||||
return Task.FromResult(UpdateInclude(entity, propertyPredicates));
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, IEnumerable<string> propertyNames)
|
||||
{
|
||||
return Task.FromResult(UpdateInclude(entity, propertyNames));
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates)
|
||||
{
|
||||
return Task.FromResult(UpdateInclude(entity, propertyPredicates));
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, string[] propertyNames)
|
||||
{
|
||||
var entityEntry = UpdateInclude(entity, propertyNames);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates)
|
||||
{
|
||||
var entityEntry = UpdateInclude(entity, propertyPredicates);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, IEnumerable<string> propertyNames)
|
||||
{
|
||||
var entityEntry = UpdateInclude(entity, propertyNames);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates)
|
||||
{
|
||||
var entityEntry = UpdateInclude(entity, propertyPredicates);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateIncludeAsync(entity, propertyNames);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateIncludeAsync(entity, propertyPredicates);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, IEnumerable<string> propertyNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateIncludeAsync(entity, propertyNames);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateIncludeAsync(entity, propertyPredicates);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateExclude(TEntity entity, IEnumerable<string> propertyNames)
|
||||
{
|
||||
var entityEntry = ChangeEntityState(entity, EntityState.Modified);
|
||||
foreach (var propertyName in propertyNames)
|
||||
{
|
||||
EntityPropertyEntry(entity, propertyName).IsModified = false;
|
||||
}
|
||||
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateExclude(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates)
|
||||
{
|
||||
var entityEntry = ChangeEntityState(entity, EntityState.Modified);
|
||||
foreach (var propertyPredicate in propertyPredicates)
|
||||
{
|
||||
EntityPropertyEntry(entity, propertyPredicate).IsModified = false;
|
||||
}
|
||||
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, string[] propertyNames)
|
||||
{
|
||||
return Task.FromResult(UpdateExclude(entity, propertyNames));
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates)
|
||||
{
|
||||
return Task.FromResult(UpdateExclude(entity, propertyPredicates));
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, IEnumerable<string> propertyNames)
|
||||
{
|
||||
return Task.FromResult(UpdateExclude(entity, propertyNames));
|
||||
}
|
||||
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates)
|
||||
{
|
||||
return Task.FromResult(UpdateExclude(entity, propertyPredicates));
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, string[] propertyNames)
|
||||
{
|
||||
var entityEntry = UpdateExclude(entity, propertyNames);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates)
|
||||
{
|
||||
var entityEntry = UpdateExclude(entity, propertyPredicates);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, IEnumerable<string> propertyNames)
|
||||
{
|
||||
var entityEntry = UpdateExclude(entity, propertyNames);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates)
|
||||
{
|
||||
var entityEntry = UpdateExclude(entity, propertyPredicates);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateExcludeAsync(entity, propertyNames);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateExcludeAsync(entity, propertyPredicates);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, IEnumerable<string> propertyNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateExcludeAsync(entity, propertyNames);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await UpdateExcludeAsync(entity, propertyPredicates);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete
|
||||
public virtual EntityEntry<TEntity> Delete(TEntity entity)
|
||||
{
|
||||
return Entities.Remove(entity);
|
||||
}
|
||||
|
||||
public virtual void Delete(params TEntity[] entities)
|
||||
{
|
||||
Entities.RemoveRange(entities);
|
||||
}
|
||||
|
||||
public virtual void Delete(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Entities.RemoveRange(entities);
|
||||
}
|
||||
|
||||
public virtual Task<EntityEntry<TEntity>> DeleteAsync(TEntity entity)
|
||||
{
|
||||
return Task.FromResult(Delete(entity));
|
||||
}
|
||||
|
||||
public virtual Task DeleteAsync(params TEntity[] entities)
|
||||
{
|
||||
Delete(entities);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task DeleteAsync(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Delete(entities);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual EntityEntry<TEntity> DeleteNow(TEntity entity)
|
||||
{
|
||||
var entityEntry = Delete(entity);
|
||||
SaveNow();
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual void DeleteNow(params TEntity[] entities)
|
||||
{
|
||||
Delete(entities);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public virtual void DeleteNow(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Delete(entities);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public virtual async Task<EntityEntry<TEntity>> DeleteNowAsync(TEntity entity, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entityEntry = await DeleteAsync(entity);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
public virtual async Task DeleteNowAsync(params TEntity[] entities)
|
||||
{
|
||||
await DeleteAsync(entities);
|
||||
await SaveNowAsync();
|
||||
}
|
||||
|
||||
public virtual async Task DeleteNowAsync(TEntity[] entities, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await DeleteAsync(entities);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await DeleteAsync(entities);
|
||||
await SaveNowAsync(cancellationToken);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EntityEntry
|
||||
|
||||
/// <summary>
|
||||
/// 将实体加入数据上下文托管
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns>EntityEntry</returns>
|
||||
public virtual EntityEntry Entry(object entity)
|
||||
{
|
||||
return dbContext.Entry(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将实体加入数据上下文托管
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns></returns>
|
||||
public virtual EntityEntry<TEntity> Entry(TEntity entity)
|
||||
{
|
||||
return dbContext.Entry(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取实体状态
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns></returns>
|
||||
public virtual EntityState EntityEntryState(object entity)
|
||||
{
|
||||
return Entry(entity).State;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取实体状态
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns>EntityState</returns>
|
||||
public virtual EntityState EntityEntryState(TEntity entity)
|
||||
{
|
||||
return Entry(entity).State;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将实体属性加入托管
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <param name="propertyName">属性名</param>
|
||||
/// <returns>PropertyEntry</returns>
|
||||
public virtual PropertyEntry EntityPropertyEntry(object entity, string propertyName)
|
||||
{
|
||||
return Entry(entity).Property(propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将实体属性加入托管
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <param name="propertyName">属性名</param>
|
||||
/// <returns>PropertyEntry</returns>
|
||||
public virtual PropertyEntry EntityPropertyEntry(TEntity entity, string propertyName)
|
||||
{
|
||||
return Entry(entity).Property(propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将实体属性加入托管
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">属性类型</typeparam>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <param name="propertyPredicate">属性表达式</param>
|
||||
/// <returns>PropertyEntry</returns>
|
||||
public virtual PropertyEntry<TEntity, TProperty> EntityPropertyEntry<TProperty>(TEntity entity, Expression<Func<TEntity, TProperty>> propertyPredicate)
|
||||
{
|
||||
return Entry(entity).Property(propertyPredicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 改变实体状态
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <param name="entityState">实体状态</param>
|
||||
/// <returns>EntityEntry</returns>
|
||||
public virtual EntityEntry ChangeEntityState(object entity, EntityState entityState)
|
||||
{
|
||||
var entityEntry = Entry(entity);
|
||||
entityEntry.State = entityState;
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 改变实体状态
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <param name="entityState">实体状态</param>
|
||||
/// <returns>EntityEntry{TEntity}</returns>
|
||||
public virtual EntityEntry<TEntity> ChangeEntityState(TEntity entity, EntityState entityState)
|
||||
{
|
||||
var entityEntry = Entry(entity);
|
||||
entityEntry.State = entityState;
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 改变实体状态
|
||||
/// </summary>
|
||||
/// <param name="entityEntry">实体条目</param>
|
||||
/// <param name="entityState">实体状态</param>
|
||||
/// <returns>EntityEntry</returns>
|
||||
public virtual EntityEntry ChangeEntityState(EntityEntry entityEntry, EntityState entityState)
|
||||
{
|
||||
entityEntry.State = entityState;
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 改变实体状态
|
||||
/// </summary>
|
||||
/// <param name="entityEntry">实体条目</param>
|
||||
/// <param name="entityState">实体状态</param>
|
||||
/// <returns>EntityEntry{TEntity}</returns>
|
||||
public virtual EntityEntry<TEntity> ChangeEntityState(EntityEntry<TEntity> entityEntry, EntityState entityState)
|
||||
{
|
||||
entityEntry.State = entityState;
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否被附加
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns>bool</returns>
|
||||
public virtual bool IsAttached(object entity)
|
||||
{
|
||||
return EntityEntryState(entity) != EntityState.Detached;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否被附加
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns>bool</returns>
|
||||
public virtual bool IsAttached(TEntity entity)
|
||||
{
|
||||
return EntityEntryState(entity) != EntityState.Detached;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 附加实体
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns>EntityEntry</returns>
|
||||
public virtual EntityEntry Attach(object entity)
|
||||
{
|
||||
return dbContext.Attach(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 附加实体
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
/// <returns>EntityEntry</returns>
|
||||
public virtual EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
return dbContext.Attach(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 附加多个实体
|
||||
/// </summary>
|
||||
/// <param name="entities">多个实体</param>
|
||||
public virtual void AttachRange(params object[] entities)
|
||||
{
|
||||
dbContext.AttachRange(entities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 附加多个实体
|
||||
/// </summary>
|
||||
/// <param name="entities">多个实体</param>
|
||||
public virtual void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
dbContext.AttachRange(entities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消附加实体
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
public virtual void Detach(object entity)
|
||||
{
|
||||
ChangeEntityState(entity, EntityState.Detached);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消附加实体
|
||||
/// </summary>
|
||||
/// <param name="entity">实体</param>
|
||||
public virtual void Detach(TEntity entity)
|
||||
{
|
||||
ChangeEntityState(entity, EntityState.Detached);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消附加实体
|
||||
/// </summary>
|
||||
/// <param name="entityEntry">实体条目</param>
|
||||
public virtual void Detach(EntityEntry entityEntry)
|
||||
{
|
||||
ChangeEntityState(entityEntry, EntityState.Detached);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消附加实体
|
||||
/// </summary>
|
||||
/// <param name="entityEntry">实体条目</param>
|
||||
public virtual void Detach(EntityEntry<TEntity> entityEntry)
|
||||
{
|
||||
ChangeEntityState(entityEntry, EntityState.Detached);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
using CloudBuilder.Core.DatabaseAccessor.Entity;
|
||||
using CloudBuilder.Core.DependencyInjection.EFCore;
|
||||
using CloudBuilder.Core.Policy;
|
||||
using CloudBuilder.Core.Service;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor
|
||||
{
|
||||
public class SecondaryDbContext : DbContext
|
||||
{
|
||||
public const string SECONDARY_DB_CONTEXT = "SecondaryDbContext";
|
||||
|
||||
public IEnumerable<IMasterRegistEntityType<ModelBuilder>> _entityManagers;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IHttpContextAccessor httpContextAccessor;
|
||||
|
||||
public SecondaryDbContext(DbContextOptions<SecondaryDbContext> options,
|
||||
IEnumerable<IMasterRegistEntityType<ModelBuilder>> entityManagers,
|
||||
IServiceProvider serviceProvider,
|
||||
IHttpContextAccessor httpContextAccessor) : base(options)
|
||||
{
|
||||
_entityManagers = entityManagers;
|
||||
_serviceProvider = serviceProvider;
|
||||
this.httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
SavingChangesEvent();
|
||||
return base.SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex.Message.Contains("data may have been modified or deleted since entities were loaded."))
|
||||
{
|
||||
throw new ValidatedException(CoreMessagePolicy.GetInstance().ComposeMessage(CoreMessagePolicy.THE_DATA_HAS_BEEN_MODIFIED));
|
||||
}
|
||||
throw new ValidatedException(ex.InnerException?.Message ?? ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void SavingChangesEvent()
|
||||
{
|
||||
var entities = this.ChangeTracker.Entries()
|
||||
.Where(u => (u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added)).ToList();
|
||||
if (entities == null || entities.Count < 1) return;
|
||||
|
||||
string uid = this.httpContextAccessor.HttpContext?.User?.Identity?.Name;
|
||||
|
||||
if (string.IsNullOrEmpty(uid))
|
||||
{
|
||||
uid = string.Empty;
|
||||
string token = GetJwtBearerToken(httpContextAccessor.HttpContext!);
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonWebToken json = new JsonWebTokenHandler().ReadJsonWebToken(token);
|
||||
uid = json.GetClaim(ClaimPolicy.CLAINM_USERID).Value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (!(entity.State == EntityState.Added || entity.State == EntityState.Modified)) continue;
|
||||
|
||||
// 获取所有实体有效属性,排除 [NotMapper] 属性
|
||||
var props = entity.OriginalValues.Properties;
|
||||
|
||||
// 获取实体当前(现在)的值
|
||||
var currentValues = entity.CurrentValues;
|
||||
|
||||
// 遍历所有属性
|
||||
foreach (var prop in props)
|
||||
{
|
||||
// 获取属性名
|
||||
var propName = prop.Name;
|
||||
if (propName == IEntityAudited.CREATED_BY && entity.State == EntityState.Added)
|
||||
{
|
||||
currentValues[propName] = uid;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName == IEntityAudited.CREATED_DATETIME && entity.State == EntityState.Added)
|
||||
{
|
||||
currentValues[propName] = DateTime.Now;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName == IEntityAudited.UPDATED_BY)
|
||||
{
|
||||
currentValues[propName] = uid;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName == IEntityAudited.UPDATED_DATETIME)
|
||||
{
|
||||
currentValues[propName] = DateTime.Now;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
foreach (IMasterRegistEntityType<ModelBuilder> entityManager in _entityManagers)
|
||||
{
|
||||
entityManager.RegistEntity(builder);
|
||||
}
|
||||
|
||||
base.OnModelCreating(builder);
|
||||
}
|
||||
|
||||
public string GetJwtBearerToken(HttpContext httpContext, string headerKey = "Authorization", string tokenPrefix = "Bearer ")
|
||||
{
|
||||
if (httpContext == null) return null;
|
||||
// 判断请求报文头中是否有 "Authorization" 报文头
|
||||
var bearerToken = httpContext.Request.Headers[headerKey].ToString();
|
||||
if (string.IsNullOrWhiteSpace(bearerToken)) return default;
|
||||
|
||||
var prefixLenght = tokenPrefix.Length;
|
||||
return bearerToken.StartsWith(tokenPrefix, true, null) && bearerToken.Length > prefixLenght ? bearerToken[prefixLenght..] : default;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CloudBuilder.Core.DatabaseAccessor.Entity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor
|
||||
{
|
||||
public class UnitOfWork : IUnitOfWork
|
||||
{
|
||||
private readonly List<DbContext> _dbContexts = new List<DbContext>();
|
||||
private DbTransaction _transaction;
|
||||
private DbConnection _connection;
|
||||
private DbContext _dbContext;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个<see cref="UnitOfWork"/>类型的新实例
|
||||
/// </summary>
|
||||
public UnitOfWork([FromKeyedServices(MasterDbContext.MASTER_DB_CONTEXT)] DbContext context)
|
||||
{
|
||||
_dbContext = context;
|
||||
_dbContexts.Add(_dbContext);
|
||||
_connection = _dbContext.Database.GetDbConnection();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取 事务是否已提交
|
||||
/// </summary>
|
||||
public bool HasCommitted { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加DbContext共享事务
|
||||
/// </summary>
|
||||
public void AddDbContext(DbContext dbContext)
|
||||
{
|
||||
_dbContexts.Add(dbContext);
|
||||
}
|
||||
|
||||
public DbContext GetDbContext()
|
||||
{
|
||||
return _dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对数据库连接开启事务
|
||||
/// </summary>
|
||||
public virtual void BeginOrUseTransaction()
|
||||
{
|
||||
if (_dbContexts.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_transaction?.Connection == null)
|
||||
{
|
||||
if (_connection.State != ConnectionState.Open)
|
||||
{
|
||||
_connection.Open();
|
||||
}
|
||||
|
||||
_transaction = _connection.BeginTransaction();
|
||||
}
|
||||
|
||||
foreach (DbContext context in _dbContexts)
|
||||
{
|
||||
if (context.Database.CurrentTransaction != null && context.Database.CurrentTransaction.GetDbTransaction() == _transaction)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if (context.IsRelationalTransaction())
|
||||
//{
|
||||
//共享事务仅限关系数据库
|
||||
context.Database.UseTransaction(_transaction);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// context.Database.BeginTransaction();
|
||||
//}
|
||||
}
|
||||
|
||||
HasCommitted = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对数据库连接开启事务
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">异步取消标记</param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task BeginOrUseTransactionAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_dbContexts.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_transaction?.Connection == null)
|
||||
{
|
||||
if (_connection.State != ConnectionState.Open)
|
||||
{
|
||||
await _connection.OpenAsync(cancellationToken);
|
||||
}
|
||||
|
||||
_transaction = _connection.BeginTransaction();
|
||||
}
|
||||
|
||||
foreach (DbContext context in _dbContexts)
|
||||
{
|
||||
if (context.Database.CurrentTransaction != null && context.Database.CurrentTransaction.GetDbTransaction() == _transaction)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if (context.IsRelationalTransaction())
|
||||
//{
|
||||
context.Database.UseTransaction(_transaction);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// await context.Database.BeginTransactionAsync(cancellationToken);
|
||||
//}
|
||||
}
|
||||
|
||||
HasCommitted = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提交当前上下文的事务更改
|
||||
/// </summary>
|
||||
public virtual void Commit()
|
||||
{
|
||||
if (HasCommitted || _dbContexts.Count == 0 || _transaction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_transaction.Commit();
|
||||
foreach (DbContext context in _dbContexts)
|
||||
{
|
||||
//if (context.IsRelationalTransaction())
|
||||
//{
|
||||
context.Database.CurrentTransaction.Dispose();
|
||||
//关系型数据库共享事务
|
||||
continue;
|
||||
//}
|
||||
|
||||
//context.Database.CommitTransaction();
|
||||
}
|
||||
|
||||
HasCommitted = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回滚所有事务
|
||||
/// </summary>
|
||||
public virtual void Rollback()
|
||||
{
|
||||
if (_transaction?.Connection != null)
|
||||
{
|
||||
_transaction.Rollback();
|
||||
}
|
||||
foreach (var context in _dbContexts)
|
||||
{
|
||||
//if (context.IsRelationalTransaction())
|
||||
//{
|
||||
CleanChanges(context);
|
||||
if (context.Database.CurrentTransaction != null)
|
||||
{
|
||||
//context.Database.CurrentTransaction.Rollback();
|
||||
context.Database.CurrentTransaction.Dispose();
|
||||
}
|
||||
continue;
|
||||
//}
|
||||
//context.Database.RollbackTransaction();
|
||||
}
|
||||
HasCommitted = true;
|
||||
}
|
||||
|
||||
private static void CleanChanges(DbContext context)
|
||||
{
|
||||
var entries = context.ChangeTracker.Entries().ToArray();
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
entry.State = EntityState.Detached;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_transaction?.Dispose();
|
||||
foreach (DbContext context in _dbContexts)
|
||||
{
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor
|
||||
{
|
||||
/*
|
||||
事务范围不匹配:TransactionScope 管理的是分布式事务,但对于单个数据库连接,通常不需要分布式事务。
|
||||
OnActionExecutionAsync 是 ASP.NET Core 中异步的 Action 过滤器执行方法。
|
||||
// OnActionExecuting: Action 执行前
|
||||
[开始事务]
|
||||
↓
|
||||
[Action 方法执行]
|
||||
↓
|
||||
// OnActionExecuted: Action 执行后(无论是否异常)
|
||||
[检查异常]
|
||||
[提交或回滚事务]
|
||||
*/
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class UnitOfWorkAttribute : ActionFilterAttribute
|
||||
{
|
||||
private TransactionScope _transactionScope;
|
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
_transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew,
|
||||
new TransactionOptions
|
||||
{
|
||||
IsolationLevel = IsolationLevel.ReadCommitted,
|
||||
Timeout = TransactionManager.MaximumTimeout
|
||||
});
|
||||
|
||||
base.OnActionExecuting(context);
|
||||
}
|
||||
|
||||
public override void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
if (_transactionScope != null)
|
||||
{
|
||||
if (context.Exception == null)
|
||||
{
|
||||
//必须要有 SaveChanges() 调用,否则数据只会停留在内存中,不会真正保存到数据库。
|
||||
_transactionScope.Complete();
|
||||
}
|
||||
_transactionScope.Dispose();
|
||||
}
|
||||
|
||||
base.OnActionExecuted(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudBuilder.Core.DatabaseAccessor
|
||||
{
|
||||
public class WebService
|
||||
{
|
||||
public WebService(IServiceCollection services)
|
||||
{
|
||||
Services = services;
|
||||
}
|
||||
|
||||
public IServiceCollection Services { get; }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user