zhengyiming
2025-08-04 7da5c077a94f883ae7ce2def5dbec4a2e66c5856
1
2
3
4
5
6
7
8
9
10
11
12
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
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
using Furion;
using Furion.DatabaseAccessor;
using Furion.DistributedIDGenerator;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
 
namespace FlexJobApi.Core
{
    public static class DbUtils
    {
        /// <summary>
        /// 生成实体
        /// </summary>
        /// <param name="modelBuilder"></param>
        /// <param name="dbContextLocator"></param>
        /// <returns></returns>
        public static async Task BuildEntity(ModelBuilder modelBuilder, Type dbContextLocator = null)
        {
            var xmlDoc = await XmlDocUtils.GetXmlDocAsync();
            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                Console.WriteLine($"正在生成表:{entityType.Name}");
                // 获取实体类的XML注释,并设置为表注释
                var entityBuilder = modelBuilder.Entity(entityType.ClrType);
                string typeComment = (await entityType.ClrType.GetXmlDocMemberAsync(xmlDoc))?.Summary;
                if (!string.IsNullOrEmpty(typeComment))
                {
                    Console.WriteLine($"正在生成表注释:{entityType.Name}-{typeComment}");
                    entityBuilder.ToTable(it => it.HasComment(typeComment));
                }
                // 获取实体属性的XML注释,并设置为列注释
                var properties = entityType.ClrType.GetProperties()
                    .Where(p =>
                        p.CanRead
                        && p.CanWrite
                        && !typeof(System.Collections.ICollection).IsAssignableFrom(p.PropertyType)
                        && (p.PropertyType.IsClass ? p.PropertyType.FullName.Contains("System.") : true));
                foreach (var property in properties)
                {
                    string propComment = (await property.GetXmlDocMemberAsync(xmlDoc))?.Summary;
                    if (!string.IsNullOrEmpty(propComment))
                    {
                        Console.WriteLine($"正在生成属性注释:{property.Name}-{propComment}");
                        entityBuilder.Property(property.Name).HasComment(propComment);
                    }
                }
 
                if (typeof(CommonEntity).IsAssignableFrom(entityType.ClrType))
                {
                    // 构建筛选条件:IsDeleted == false
                    var parameter = Expression.Parameter(entityType.ClrType, "e");
                    var property = Expression.Property(parameter, "IsDeleted");
                    var constant = Expression.Constant(false);
                    var equal = Expression.Equal(property, constant);
                    var lambda = Expression.Lambda(equal, parameter);
 
                    // 添加全局筛选器
                    modelBuilder.Entity(entityType.ClrType).HasQueryFilter(lambda);
                }
            }
        }
 
        public static void SavingChangesEvent(DbContextEventData eventData, InterceptionResult<int> result)
        {
            // 获取当前事件对应上下文
            var dbContext = eventData.Context;
 
            // 强制重新检查一边实体更改信息
            // dbContext.ChangeTracker.DetectChanges();
 
            // 获取所有更改,删除,新增的实体
            var dbAuditLogIgnoreType = typeof(IDbAuditLogIgnore);
            var physicalDeletionType = typeof(IPhysicalDeletion);
            var entities = dbContext.ChangeTracker.Entries()
                .Where(u =>
                    u.GetType() != typeof(DbAuditLog)
                    && (u.State == EntityState.Modified
                    || u.State == EntityState.Deleted
                    || u.State == EntityState.Added))
                .ToList();
 
            // 通过请求中获取当前操作人
            var logier = JwtUtils.GetCurrentLogier();
 
            // 获取所有已更改的实体
            foreach (var entity in entities)
            {
                // 获取实体类型
                var entityType = entity.Entity.GetType();
 
                if (entity.State == EntityState.Added)
                {
                    // 赋值创建日期
                    var prop = entity.Property(nameof(CommonEntity.CreatedTime));
                    if (prop != null && prop.CurrentValue?.ToDateTime() == null)
                    {
                        prop.CurrentValue = DateTimeOffset.Now;
                    }
 
                    // 生成Id
                    prop = entity.Property(nameof(CommonEntity.Id));
                    var defaultValue = Activator.CreateInstance(prop.Metadata.ClrType);
                    if (prop != null && (prop.CurrentValue == null || prop.CurrentValue.Equals(defaultValue)))
                    {
                        prop.CurrentValue = IDGen.NextID();
                    }
 
                    // 赋值用户信息Id
                    prop = entity.Property(nameof(CommonEntity.CreatedUserInfoId));
                    if (prop != null && prop.CurrentValue == null)
                    {
                        prop.CurrentValue = logier?.UserInfoId;
                    }
 
                    // 赋值跟踪Id
                    prop = entity.Property(nameof(CommonEntity.TraceId));
                    if (prop != null)
                    {
                        prop.CurrentValue = App.GetTraceId();
                    }
                }
                else
                {
                    // 赋值修改日期
                    var prop = entity.Property(nameof(CommonEntity.UpdatedTime));
                    if (prop != null)
                    {
                        prop.CurrentValue = DateTimeOffset.Now;
                    }
 
                    // 赋值用户信息Id
                    prop = entity.Property(nameof(CommonEntity.UpdatedUserInfoId));
                    if (prop != null)
                    {
                        prop.CurrentValue = logier?.UserInfoId;
                    }
 
                    // 赋值跟踪Id
                    prop = entity.Property(nameof(CommonEntity.TraceId));
                    if (prop != null)
                    {
                        prop.CurrentValue = App.GetTraceId();
                    }
 
                    // 软删除
                    if (entity.State == EntityState.Deleted && !physicalDeletionType.IsAssignableFrom(entityType))
                    {
                        entity.State = EntityState.Modified;
 
                        prop = entity.Property(nameof(CommonEntity.IsDeleted));
                        if (prop != null)
                        {
                            prop.CurrentValue = true;
                        }
                    }
                }
 
                if (dbAuditLogIgnoreType.IsAssignableFrom(entityType))
                {
                    continue;
                }
 
                Db.GetRepository<DbAuditLog, LogDbContextLocator>().InsertNow(new DbAuditLog
                {
                    Id = IDGen.NextID(),
                    TableName = entityType.Name,
                    PrimaryKey = (Guid)entity.Property("Id").CurrentValue,
                    NewValues = entity.State == EntityState.Added || entity.State == EntityState.Modified
                        ? GetPropertyValuesAsJson(entity)
                        : null,
                    OldValues = entity.State == EntityState.Deleted || entity.State == EntityState.Modified
                        ? GetPropertyValuesAsJson(entity, entity.State == EntityState.Modified)
                        : null,
                    Operate = entity.State == EntityState.Added
                        ? EnumDbAuditOperate.Added
                        : entity.State == EntityState.Modified
                        ? EnumDbAuditOperate.Modified
                        : EnumDbAuditOperate.Deleted,
                    TraceId = App.GetTraceId(),
                    CreatedTime = DateTime.Now,
                    CreatedUserInfoId = logier?.UserInfoId,
                });
            }
        }
 
        private static string GetPropertyValuesAsJson(EntityEntry entry, bool getOldValues = false)
        {
            var properties = entry.Properties
                .Where(p => getOldValues ? p.IsModified : true)
                .ToDictionary(p => p.Metadata.Name, p => getOldValues ? p.OriginalValue : p.CurrentValue);
 
            return JsonConvert.SerializeObject(properties);
        }
    }
}