1
schangxiang@126.com
2024-04-23 64ae2832a77733d4993b667d36549ccf315bbd52
1
已添加2个文件
已删除3个文件
29829 ■■■■■ 文件已修改
iWare_RawMaterialWarehouse_Wms/Admin.NET.Database.Migrations/Migrations/20240413040247_v1.0.1.Designer.cs 13180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iWare_RawMaterialWarehouse_Wms/Admin.NET.Database.Migrations/Migrations/20240413040247_v1.0.1.cs 3102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iWare_RawMaterialWarehouse_Wms/Admin.NET.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs 13178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iWare_RawMaterialWarehouse_Wms/Admin.NET.EntityFramework.Core/DbContexts/DefaultDbContext.cs 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iWare_RawMaterialWarehouse_Wms/Admin.NET.EntityFramework.Core/DbContexts/MultiTenantDbContext.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iWare_RawMaterialWarehouse_Wms/Admin.NET.Database.Migrations/Migrations/20240413040247_v1.0.1.Designer.cs
ÎļþÒÑɾ³ý
iWare_RawMaterialWarehouse_Wms/Admin.NET.Database.Migrations/Migrations/20240413040247_v1.0.1.cs
ÎļþÒÑɾ³ý
iWare_RawMaterialWarehouse_Wms/Admin.NET.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs
ÎļþÒÑɾ³ý
iWare_RawMaterialWarehouse_Wms/Admin.NET.EntityFramework.Core/DbContexts/DefaultDbContext.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,307 @@
using Admin.NET.Core;
using Admin.NET.Core.Entity;
using Furion;
using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System.Linq.Expressions;
using Yitter.IdGenerator;
namespace Admin.NET.EntityFramework.Core
{
    [AppDbContext("DefaultConnection", DbProvider.SqlServer)]
    public class DefaultDbContext : AppDbContext<DefaultDbContext>, IModelBuilderFilter
    {
        public DefaultDbContext(DbContextOptions<DefaultDbContext> options) : base(options)
        {
            // å¯ç”¨å®žä½“数据更改监听
            EnabledEntityChangedListener = true;
            // å¿½ç•¥ç©ºå€¼æ›´æ–°
            InsertOrUpdateIgnoreNullValues = true;
        }
        /// <summary>
        /// èŽ·å–ç§Ÿæˆ·Id
        /// </summary>
        /// <returns></returns>
        //public object GetTenantId()
        //{
        //    // æµç¨‹ä¸­æ²¡æœ‰ç”¨åˆ°å¤šç§Ÿæˆ· è¿™é‡Œé»˜è®¤è¿”回一个租户
        //    if (App.User == null) return 142307070918780;
        //    return Convert.ToInt64(App.User.FindFirst(ClaimConst.TENANT_ID)?.Value);
        //}
        protected override void OnModelCreating(ModelBuilder builder)
        {
            if (Database.ProviderName == DbProvider.Sqlite)
            {
                // SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations
                // here: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#query-limitations
                // To work around this, when the Sqlite database provider is used, all model properties of type DateTimeOffset
                // use the DateTimeOffsetToBinaryConverter
                // Based on: https://github.com/aspnet/EntityFrameworkCore/issues/10784#issuecomment-415769754
                // This only supports millisecond precision, but should be sufficient for most use cases.
                foreach (var entityType in builder.Model.GetEntityTypes())
                {
                    var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == typeof(DateTimeOffset)
                                                                                || p.PropertyType == typeof(DateTimeOffset?));
                    foreach (var property in properties)
                    {
                        builder
                            .Entity(entityType.Name)
                            .Property(property.Name)
                            .HasConversion(new DateTimeOffsetToBinaryConverter());
                    }
                }
            }
            // å¤„理mysql时区问题 https://gitee.com/dotnetchina/Furion/issues/I3RSCO#note_5685893_link
            else if (Database.ProviderName == DbProvider.MySql || Database.ProviderName == DbProvider.MySqlOfficial)
            {
                var converter = new ValueConverter<DateTimeOffset, DateTime>(v => v.LocalDateTime, v => v);
                // æ‰«æç¨‹åºé›†ï¼ŒèŽ·å–æ•°æ®åº“å®žä½“ç›¸å…³ç±»åž‹
                var types = App.EffectiveTypes.Where(t => (typeof(IPrivateEntity).IsAssignableFrom(t) || typeof(IPrivateModelBuilder).IsAssignableFrom(t))
                     && t.IsClass && !t.IsAbstract && !t.IsGenericType && !t.IsInterface && !t.IsDefined(typeof(ManualAttribute), true));
                if (types.Any())
                {
                    foreach (var item in types)
                    {
                        if (item.IsSubclassOf(typeof(DEntityBase)) || item.IsSubclassOf(typeof(EntityBase)))
                        {
                            foreach (var property in item.GetProperties())
                            {
                                if (property.PropertyType == typeof(DateTimeOffset?) || property.PropertyType == typeof(DateTimeOffset))
                                {
                                    builder.Entity(item).Property(property.Name).HasConversion(converter);
                                }
                            }
                        }
                    }
                }
            }
            base.OnModelCreating(builder);
        }
        /// <summary>
        /// é…ç½®ç§Ÿæˆ·Id过滤器
        /// </summary>
        /// <param name="modelBuilder"></param>
        /// <param name="entityBuilder"></param>
        /// <param name="dbContext"></param>
        /// <param name="dbContextLocator"></param>
        public void OnCreating(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            // é…ç½®å‡åˆ é™¤è¿‡æ»¤å™¨
            LambdaExpression expression = FakeDeleteQueryFilterExpression(entityBuilder, dbContext);
            if (expression != null)
                entityBuilder.HasQueryFilter(expression);
            // é…ç½®æ•°æ®æƒé™åŠ¨æ€è¡¨è¾¾å¼
            LambdaExpression dataScopesExpression = DataScopesFilterExpression(entityBuilder, dbContext);
            if (dataScopesExpression != null)
                entityBuilder.HasQueryFilter(dataScopesExpression);
        }
        protected override void SavingChangesEvent(DbContextEventData eventData, InterceptionResult<int> result)
        {
            // èŽ·å–å½“å‰äº‹ä»¶å¯¹åº”ä¸Šä¸‹æ–‡
            var dbContext = eventData.Context;
            // èŽ·å–æ‰€æœ‰æ›´æ”¹ï¼Œåˆ é™¤ï¼Œæ–°å¢žçš„å®žä½“ï¼Œä½†æŽ’é™¤å®¡è®¡å®žä½“ï¼ˆé¿å…æ­»å¾ªçŽ¯ï¼‰
            var entities = dbContext.ChangeTracker.Entries()
                  .Where(u => u.Entity.GetType() != typeof(SysLogAudit) && u.Entity.GetType() != typeof(SysLogOp) &&
                              u.Entity.GetType() != typeof(SysLogVis) && u.Entity.GetType() != typeof(SysLogEx) &&
                        (u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added)).ToList();
            if (entities == null || entities.Count < 1) return;
            //// åˆ¤æ–­æ˜¯å¦æ˜¯æ¼”示环境
            //var demoEnvFlag = App.GetService<ISysConfigService>().GetDemoEnvFlag().GetAwaiter().GetResult();
            //if (demoEnvFlag)
            //{
            //    var sysUser = entities.Find(u => u.Entity.GetType() == typeof(SysUser));
            //    if (sysUser == null || string.IsNullOrEmpty((sysUser.Entity as SysUser).LastLoginTime.ToString())) // æŽ’除登录
            //        throw Oops.Oh(ErrorCode.D1200);
            //}
            // å½“前操作者信息
            var userId = App.User?.FindFirst(ClaimConst.CLAINM_USERID)?.Value;
            //读取的用户名改为 æ˜µç§°ï¼Œè€Œä¸æ˜¯è´¦å· ã€Editby shaocx,2024-04-20】
            //var userName = App.User?.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value;
            var userName = App.User?.FindFirst(ClaimConst.CLAINM_NAME)?.Value;
            // å½“前操作者机构信息
            var orgId = App.User?.FindFirst(ClaimConst.CLAINM_ORGID)?.Value;
            var orgName = App.User?.FindFirst(ClaimConst.CLAINM_ORGNAME)?.Value;
            foreach (var entity in entities)
            {
                if (entity.Entity.GetType().IsSubclassOf(typeof(DEntityBase)))
                {
                    var obj = entity.Entity as DEntityBase;
                    if (entity.State == EntityState.Added)
                    {
                        obj.Id = obj.Id == 0 ? YitIdHelper.NextId() : obj.Id;
                        obj.CreatedTime = DateTimeOffset.Now;
                        if (!string.IsNullOrEmpty(userId))
                        {
                            obj.CreatedUserId = long.Parse(userId);
                            obj.CreatedUserName = userName;
                            if (entity.Entity.GetType().GetInterface(typeof(IDataPermissions).Name) != null)
                            {
                                ((IDataPermissions)obj).CreatedUserOrgId = long.Parse(orgId);
                                ((IDataPermissions)obj).CreatedUserOrgName = orgName;
                            }
                        }
                    }
                    else if (entity.State == EntityState.Modified)
                    {
                        // æŽ’除创建人
                        entity.Property(nameof(DEntityBase.CreatedUserId)).IsModified = false;
                        entity.Property(nameof(DEntityBase.CreatedUserName)).IsModified = false;
                        // æŽ’除创建日期
                        entity.Property(nameof(DEntityBase.CreatedTime)).IsModified = false;
                        obj.UpdatedTime = DateTimeOffset.Now;
                        if (!string.IsNullOrEmpty(userId))
                        {
                            obj.UpdatedUserId = long.Parse(userId);
                            obj.UpdatedUserName = userName;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// æž„建租户Id以及假删除过滤器
        /// </summary>
        /// <param name="entityBuilder"></param>
        /// <param name="dbContext"></param>
        /// <param name="isDeletedKey"></param>
        /// <param name="filterValue"></param>
        /// <returns></returns>
        protected static LambdaExpression FakeDeleteQueryFilterExpression(EntityTypeBuilder entityBuilder, DbContext dbContext, string onTableTenantId = null, string isDeletedKey = null, object filterValue = null)
        {
            //onTableTenantId ??= "TenantId";
            isDeletedKey ??= "IsDeleted";
            IMutableEntityType metadata = entityBuilder.Metadata;
            //if (metadata.FindProperty(onTableTenantId) == null && metadata.FindProperty(isDeletedKey) == null)
            //{
            //    return null;
            //}
            //解决实体继承报错问题,基类表才有IsDeleted、TenantId字段
            if (metadata.BaseType != null)
            {
                return null;
            }
            Expression finialExpression = Expression.Constant(true);
            ParameterExpression parameterExpression = Expression.Parameter(metadata.ClrType, "u");
            // å‡åˆ é™¤è¿‡æ»¤å™¨
            if (metadata.FindProperty(isDeletedKey) != null)
            {
                ConstantExpression constantExpression = Expression.Constant(isDeletedKey);
                ConstantExpression right = Expression.Constant(filterValue ?? false);
                var fakeDeleteQueryExpression = Expression.Equal(Expression.Call(typeof(EF), "Property", new Type[1]
                {
                    typeof(bool)
                }, parameterExpression, constantExpression), right);
                finialExpression = Expression.AndAlso(finialExpression, fakeDeleteQueryExpression);
            }
            return Expression.Lambda(finialExpression, parameterExpression);
        }
        #region æ•°æ®æƒé™
        /// <summary>
        /// èŽ·å–ç”¨æˆ·Id
        /// </summary>
        /// <returns></returns>
        public object GetUserId()
        {
            if (App.User == null) return null;
            return App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value;
        }
        /// <summary>
        /// èŽ·å–æ•°æ®èŒƒå›´
        /// </summary>
        /// <returns></returns>
        public List<object> GetDataScopes()
        {
            var userId = this.GetUserId();
            if (userId == null)
            {
                return new List<object>();
            }
            var dataScopes = JsonUtil.FromJson<List<object>>(App.User.FindFirst(ClaimConst.DATA_SCOPES)?.Value);
            if (dataScopes != null)
            {
                return dataScopes;
            }
            return new List<object>();
        }
        /// <summary>
        /// æž„建数据范围过滤器
        /// </summary>
        /// <param name="entityBuilder"></param>
        /// <param name="dbContext"></param>
        /// <param name="onTableCreatedUserId"></param>
        /// <param name="onTableCreatedUserOrgId"></param>
        /// <param name="filterValue"></param>
        /// <returns></returns>
        protected LambdaExpression DataScopesFilterExpression(EntityTypeBuilder entityBuilder, DbContext dbContext, string onTableCreatedUserId = null, string onTableCreatedUserOrgId = null)
        {
            onTableCreatedUserId ??= nameof(IDataPermissions.CreatedUserId);//用户id字段
            onTableCreatedUserOrgId ??= nameof(IDataPermissions.CreatedUserOrgId);//用户部门字段
            IMutableEntityType metadata = entityBuilder.Metadata;
            if (metadata.FindProperty(onTableCreatedUserId) == null || metadata.FindProperty(onTableCreatedUserOrgId) == null)
            {
                return null;
            }
            Expression finialExpression = Expression.Constant(true);
            ParameterExpression parameterExpression = Expression.Parameter(metadata.ClrType, "u");
            // ä¸ªäººç”¨æˆ·æ•°æ®è¿‡æ»¤å™¨
            if (metadata.FindProperty(onTableCreatedUserId) != null)
            {
                ConstantExpression constantExpression = Expression.Constant(onTableCreatedUserId);
                MethodCallExpression right = Expression.Call(Expression.Constant(dbContext), dbContext.GetType().GetMethod("GetUserId"));
                finialExpression = Expression.AndAlso(finialExpression, Expression.Equal(Expression.Call(typeof(EF), "Property", new Type[1]
                {
                        typeof(object)
                }, parameterExpression, constantExpression), right));
            }
            //数据权限过滤器
            if (metadata.FindProperty(onTableCreatedUserOrgId) != null)
            {
                ConstantExpression constantExpression = Expression.Constant(onTableCreatedUserOrgId);
                MethodCallExpression dataScopesLeft = Expression.Call(Expression.Constant(dbContext), dbContext.GetType().GetMethod("GetDataScopes"));
                var firstOrDefaultCall = Expression.Call(typeof(EF), "Property", new Type[1]
                    {
                        typeof(object)
                    }, parameterExpression, constantExpression);
                var createdUserOrgIdQueryExpression = Expression.Call(dataScopesLeft, typeof(List<object>).GetMethod("Contains"), firstOrDefaultCall);
                finialExpression = Expression.Or(finialExpression, createdUserOrgIdQueryExpression);
            }
            return Expression.Lambda(finialExpression, parameterExpression);
        }
        #endregion æ•°æ®æƒé™
    }
}
iWare_RawMaterialWarehouse_Wms/Admin.NET.EntityFramework.Core/DbContexts/MultiTenantDbContext.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
using Admin.NET.Core;
using Furion;
using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Yitter.IdGenerator;
namespace Admin.NET.EntityFramework.Core
{
    [AppDbContext("MultiTenantConnection", DbProvider.Sqlite)]
    public class MultiTenantDbContext : AppDbContext<MultiTenantDbContext, MultiTenantDbContextLocator>
    {
        public MultiTenantDbContext(DbContextOptions<MultiTenantDbContext> options) : base(options)
        {
        }
        protected override void SavingChangesEvent(DbContextEventData eventData, InterceptionResult<int> result)
        {
            // èŽ·å–æ‰€æœ‰å·²æ›´æ”¹çš„å®žä½“
            var entities = eventData.Context.ChangeTracker.Entries()
                                    .Where(u => u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added)
                                    .ToList();
            // åˆ¤æ–­æ˜¯å¦æ˜¯æ¼”示环境
            //var demoEnvFlag = App.GetService<ISysConfigService>().GetDemoEnvFlag().GetAwaiter().GetResult();
            //if (demoEnvFlag)
            //{
            //    var sysUser = entities.Find(u => u.Entity.GetType() == typeof(SysUser));
            //    if (sysUser == null || string.IsNullOrEmpty((sysUser.Entity as SysUser).LastLoginTime.ToString())) // æŽ’除登录
            //        throw Oops.Oh(ErrorCode.D1200);
            //}
            // å½“前操作用户信息
            var userId = App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value;
            var userName = App.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value;
            foreach (var entity in entities)
            {
                if (entity.Entity.GetType().IsSubclassOf(typeof(DEntityBase<long, MultiTenantDbContextLocator>)))
                {
                    var obj = entity.Entity as DEntityBase<long, MultiTenantDbContextLocator>;
                    if (entity.State == EntityState.Added)
                    {
                        obj.Id = YitIdHelper.NextId();
                        obj.CreatedTime = DateTimeOffset.Now;
                        if (!string.IsNullOrEmpty(userId))
                        {
                            obj.CreatedUserId = long.Parse(userId);
                            obj.CreatedUserName = userName;
                        }
                    }
                    else if (entity.State == EntityState.Modified)
                    {
                        obj.UpdatedTime = DateTimeOffset.Now;
                        obj.UpdatedUserId = long.Parse(userId);
                        obj.UpdatedUserName = userName;
                    }
                }
            }
        }
    }
}