@@ -11,6 +11,8 @@ namespace Bing.Domain.Entities;
1111/// </summary>
1212public static class EntityHelper
1313{
14+ #region ID生成相关
15+
1416 /// <summary>
1517 /// ID生成器字典
1618 /// </summary>
@@ -42,6 +44,12 @@ public static class EntityHelper
4244 /// </summary>
4345 public static Func < int > IntGenerateFunc { get ; set ; } = ( ) => throw new InvalidOperationException ( "不支持 Int 作为 ID,请使用 Guid, string 或 long。" ) ;
4446
47+ /// <summary>
48+ /// 生成唯一标识 ID,默认使用 Guid 类型。
49+ /// </summary>
50+ /// <returns>生成的 Guid 值</returns>
51+ public static Guid CreateGuid ( ) => CreateKey < Guid > ( ) ;
52+
4553 /// <summary>
4654 /// 生成唯一标识 ID,支持 Guid、string、long 类型。
4755 /// </summary>
@@ -54,6 +62,22 @@ public static TKey CreateKey<TKey>()
5462 throw new InvalidOperationException ( $ "不支持的 ID 类型: { typeof ( TKey ) } ,请使用 Guid, string, long。") ;
5563 }
5664
65+ /// <summary>
66+ /// 注册自定义 ID 生成器
67+ /// </summary>
68+ /// <typeparam name="TKey">ID 类型</typeparam>
69+ /// <param name="generator">生成器函数</param>
70+ /// <exception cref="ArgumentNullException">当<paramref name="generator"/>为null时抛出</exception>
71+ public static void RegisterIdGenerator < TKey > ( Func < TKey > generator )
72+ {
73+ Check . NotNull ( generator , nameof ( generator ) ) ;
74+ _idGenerators [ typeof ( TKey ) ] = ( ) => generator ( ) ;
75+ }
76+
77+ #endregion
78+
79+ #region 实体相等性比较
80+
5781 /// <summary>
5882 /// 判断实体类型是否为多租户实体。
5983 /// </summary>
@@ -74,14 +98,13 @@ public static TKey CreateKey<TKey>()
7498 /// </returns>
7599 public static bool EntityEquals ( IEntity entity1 , IEntity entity2 )
76100 {
101+ // 基本检查
77102 if ( entity1 == null || entity2 == null )
78103 return false ;
79-
80- // 如果引用相同,则直接返回 true
81104 if ( ReferenceEquals ( entity1 , entity2 ) )
82105 return true ;
83106
84- // 如果两个实体类型不兼容,则返回 false
107+ // 类型兼容性检查
85108 var typeOfEntity1 = entity1 . GetType ( ) ;
86109 var typeOfEntity2 = entity2 . GetType ( ) ;
87110 if ( ! typeOfEntity1 . IsAssignableFrom ( typeOfEntity2 ) && ! typeOfEntity2 . IsAssignableFrom ( typeOfEntity1 ) )
@@ -91,44 +114,54 @@ public static bool EntityEquals(IEntity entity1, IEntity entity2)
91114 if ( IsMultiTenantEntity ( entity1 , entity2 ) )
92115 return AllowSameIdAcrossTenants ( entity1 , entity2 ) ;
93116
94- // 瞬时对象不视为相等
117+ // 瞬时对象检查 - 瞬时对象不视为相等
95118 if ( HasDefaultKeys ( entity1 ) && HasDefaultKeys ( entity2 ) )
96119 return false ;
97120
98- // 如果键数量不匹配,则不相等
121+ // 键数量检查
99122 var entity1Keys = entity1 . GetKeys ( ) ;
100123 var entity2Keys = entity2 . GetKeys ( ) ;
101124 if ( entity1Keys . Length != entity2Keys . Length )
102125 return false ;
103126
104- // 逐个比较主键值
105- for ( var i = 0 ; i < entity1Keys . Length ; i ++ )
106- {
107- // 如果 `entity1Key` 为 null,`entity2Key` 也必须为 null,否则不相等
108- var entity1Key = entity1Keys [ i ] ;
109- var entity2Key = entity2Keys [ i ] ;
110- if ( entity1Key == null )
111- {
112- if ( entity2Key == null )
113- continue ;
114- return false ;
115- }
127+ // 键值比较
128+ return KeysEqual ( entity1Keys , entity2Keys ) ;
129+ }
116130
117- // 如果 `entity2Key` 为 null,则不相等
118- if ( entity2Key == null )
131+ /// <summary>
132+ /// 比较两个键数组是否相等
133+ /// </summary>
134+ /// <param name="keys1">第一个键数组</param>
135+ /// <param name="keys2">第二个键数组</param>
136+ /// <returns>如果键数组相等返回true,否则返回false</returns>
137+ private static bool KeysEqual ( object [ ] keys1 , object [ ] keys2 )
138+ {
139+ for ( var i = 0 ; i < keys1 . Length ; i ++ )
140+ {
141+ var key1 = keys1 [ i ] ;
142+ var key2 = keys2 [ i ] ;
143+
144+ // 空值检查
145+ if ( key1 == null )
146+ return key2 == null ;
147+ if ( key2 == null )
119148 return false ;
120149
121- // 如果两个键值都是默认值(如 0、null、Guid.Empty),则继续比较
122- if ( Types . IsDefaultValue ( entity1Key ) && Types . IsDefaultValue ( entity2Key ) )
150+ // 默认值检查 - 如果两个键值都是默认值,则视为不相等
151+ if ( Types . IsDefaultValue ( key1 ) && Types . IsDefaultValue ( key2 ) )
123152 return false ;
124153
125- // 进行键值比较,如果不同,则返回 false
126- if ( ! entity1Key . Equals ( entity2Key ) )
154+ // 值比较
155+ if ( ! key1 . Equals ( key2 ) )
127156 return false ;
128157 }
129158 return true ;
130159 }
131160
161+ #endregion
162+
163+ #region 实体和值对象类型检查
164+
132165 /// <summary>
133166 /// 判断指定的类型是否实现了 <see cref="IEntity"/> 接口。
134167 /// </summary>
@@ -141,6 +174,38 @@ public static bool IsEntity(Type type)
141174 return typeof ( IEntity ) . IsAssignableFrom ( type ) ;
142175 }
143176
177+ /// <summary>
178+ /// 判断指定的类型是否实现了 <see cref="IEntity{TKey}"/> 接口
179+ /// </summary>
180+ /// <param name="type">要检查的类型</param>
181+ /// <param name="keyType">如果找到,则输出键类型;否则为null</param>
182+ /// <returns>是否为带主键的实体类型</returns>
183+ /// <exception cref="ArgumentNullException">当<paramref name="type"/>为null时抛出</exception>
184+ public static bool IsEntityWithId ( Type type , out Type keyType )
185+ {
186+ Check . NotNull ( type , nameof ( type ) ) ;
187+ keyType = null ;
188+
189+ foreach ( var interfaceType in type . GetInterfaces ( ) )
190+ {
191+ if ( interfaceType . GetTypeInfo ( ) . IsGenericType &&
192+ interfaceType . GetGenericTypeDefinition ( ) == typeof ( IEntity < > ) )
193+ {
194+ keyType = interfaceType . GenericTypeArguments [ 0 ] ;
195+ return true ;
196+ }
197+ }
198+
199+ return false ;
200+ }
201+
202+ /// <summary>
203+ /// 判断指定的类型是否实现了 <see cref="IEntity{TKey}"/> 泛型接口。
204+ /// </summary>
205+ /// <param name="type">要检查的类型。</param>
206+ /// <returns>如果该类型实现了 <see cref="IEntity{TKey}"/> 泛型接口,则返回 <c>true</c>;否则返回 <c>false</c>。</returns>
207+ public static bool IsEntityWithId ( Type type ) => IsEntityWithId ( type , out _ ) ;
208+
144209 /// <summary>
145210 /// 值对象判断谓词
146211 /// </summary>
@@ -153,7 +218,7 @@ public static bool IsEntity(Type type)
153218 /// 是否值对象类型
154219 /// </summary>
155220 /// <param name="type">类型</param>
156- /// <returns>是否为值对象类型。如果类型符合值对象判断条件,则返回true;否则返回false </returns>
221+ /// <returns>是否为值对象 </returns>
157222 /// <exception cref="ArgumentNullException">当<paramref name="type"/>为null时抛出</exception>
158223 public static bool IsValueObject ( Type type )
159224 {
@@ -165,11 +230,8 @@ public static bool IsValueObject(Type type)
165230 /// 是否值对象
166231 /// </summary>
167232 /// <param name="obj">对象实例</param>
168- /// <returns>是否为值对象。如果对象不为null且其类型符合值对象判断条件,则返回true;否则返回false</returns>
169- public static bool IsValueObject ( object obj )
170- {
171- return obj != null && IsValueObject ( obj . GetType ( ) ) ;
172- }
233+ /// <returns>是否为值对象</returns>
234+ public static bool IsValueObject ( object obj ) => obj != null && IsValueObject ( obj . GetType ( ) ) ;
173235
174236 /// <summary>
175237 /// 检查指定的类型是否为实体
@@ -184,25 +246,12 @@ public static void CheckEntity(Type type)
184246 throw new ArgumentException ( $ "参数 '{ type . FullName } ' 不是有效的实体类型。必须实现 { typeof ( IEntity ) . FullName } 接口。", nameof ( type ) ) ;
185247 }
186248
187- /// <summary>
188- /// 判断指定的类型是否实现了 <see cref="IEntity{TKey}"/> 泛型接口。
189- /// </summary>
190- /// <param name="type">要检查的类型。</param>
191- /// <returns>如果该类型实现了 <see cref="IEntity{TKey}"/> 泛型接口,则返回 <c>true</c>;否则返回 <c>false</c>。</returns>
192- public static bool IsEntityWithId ( Type type )
193- {
194- Check . NotNull ( type , nameof ( type ) ) ;
195- foreach ( var interfaceType in type . GetInterfaces ( ) )
196- {
197- if ( interfaceType . GetTypeInfo ( ) . IsGenericType &&
198- interfaceType . GetGenericTypeDefinition ( ) == typeof ( IEntity < > ) )
199- return true ;
200- }
201- return false ;
202- }
249+ #endregion
250+
251+ #region 主键检查
203252
204253 /// <summary>
205- /// 是否有默认标识值
254+ /// 判断实体是否有默认标识值
206255 /// </summary>
207256 /// <typeparam name="TKey">标识类型</typeparam>
208257 /// <param name="entity">实体</param>
@@ -215,18 +264,29 @@ public static bool HasDefaultId<TKey>(IEntity<TKey> entity)
215264 {
216265 if ( EqualityComparer < TKey > . Default . Equals ( entity . Id , default ! ) )
217266 return true ;
267+ return IsDefaultNumericKey ( entity . Id ) ;
268+ }
269+
270+ /// <summary>
271+ /// 判断是否为默认的数值类型键值
272+ /// </summary>
273+ /// <typeparam name="TKey">键类型</typeparam>
274+ /// <param name="id">ID值</param>
275+ /// <returns>如果是默认值返回true,否则返回false</returns>
276+ private static bool IsDefaultNumericKey < TKey > ( TKey id )
277+ {
218278 if ( typeof ( TKey ) == typeof ( int ) )
219- return Convert . ToInt32 ( entity . Id ) <= 0 ;
279+ return Convert . ToInt32 ( id ) <= 0 ;
220280 if ( typeof ( TKey ) == typeof ( long ) )
221- return Convert . ToInt64 ( entity . Id ) <= 0 ;
281+ return Convert . ToInt64 ( id ) <= 0 ;
222282 return false ;
223283 }
224284
225285 /// <summary>
226- /// 是否有默认值
286+ /// 判断实体是否有默认键值
227287 /// </summary>
228288 /// <param name="entity">实体</param>
229- /// <returns>是否为默认值。如果所有键都是默认值,则返回true;否则返回false </returns>
289+ /// <returns>是否为默认值</returns>
230290 /// <exception cref="ArgumentNullException">当<paramref name="entity"/>为null时抛出</exception>
231291 public static bool HasDefaultKeys ( IEntity entity )
232292 {
@@ -256,17 +316,17 @@ private static bool IsDefaultKeyValue(object value)
256316 return Types . IsDefaultValue ( value ) ;
257317 }
258318
319+ #endregion
320+
321+ #region 主键类型查找
322+
259323 /// <summary>
260324 /// 获取指定实体类型的主键类型。
261325 /// </summary>
262326 /// <typeparam name="TEntity">要获取主键类型的实体类型,必须实现 <see cref="IEntity"/> 接口。</typeparam>
263327 /// <returns>主键的类型。</returns>
264328 /// <exception cref="ArgumentException">如果 <typeparamref name="TEntity"/> 不是实体类型,则抛出异常。</exception>
265- public static Type FindPrimaryKeyType < TEntity > ( )
266- where TEntity : IEntity
267- {
268- return FindPrimaryKeyType ( typeof ( TEntity ) ) ;
269- }
329+ public static Type FindPrimaryKeyType < TEntity > ( ) where TEntity : IEntity => FindPrimaryKeyType ( typeof ( TEntity ) ) ;
270330
271331 /// <summary>
272332 /// 获取指定实体类型的主键类型。
@@ -278,18 +338,18 @@ public static Type FindPrimaryKeyType<TEntity>()
278338 public static Type FindPrimaryKeyType ( Type entityType )
279339 {
280340 Check . NotNull ( entityType , nameof ( entityType ) ) ;
281- if ( ! typeof ( IEntity ) . IsAssignableFrom ( entityType ) )
282- throw new ArgumentException ( $ "参数 '{ entityType . FullName } ' 不是有效的实体类型。必须实现 { typeof ( IEntity ) . FullName } 接口。", nameof ( entityType ) ) ;
341+ CheckEntity ( entityType ) ;
342+
343+ if ( IsEntityWithId ( entityType , out var keyType ) )
344+ return keyType ;
283345
284- foreach ( var interfaceType in entityType . GetTypeInfo ( ) . GetInterfaces ( ) )
285- {
286- if ( interfaceType . GetTypeInfo ( ) . IsGenericType &&
287- interfaceType . GetGenericTypeDefinition ( ) == typeof ( IEntity < > ) )
288- return interfaceType . GenericTypeArguments [ 0 ] ;
289- }
290346 return null ;
291347 }
292348
349+ #endregion
350+
351+ #region 表达式构建
352+
293353 /// <summary>
294354 /// 创建一个用于比较实体 ID 是否相等的 Lambda 表达式。
295355 /// </summary>
@@ -314,4 +374,6 @@ public static Expression<Func<TEntity, bool>> CreateEqualityExpressionForId<TEnt
314374 var lambdaBody = Expression . Equal ( leftExpression , rightExpression ) ; // 生成 entity.Id == id 的比较表达式
315375 return Expression . Lambda < Func < TEntity , bool > > ( lambdaBody , lambdaParam ) ;
316376 }
377+
378+ #endregion
317379}
0 commit comments