diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs
index 1863c8f938..841a7f63de 100644
--- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs
+++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs
@@ -48,7 +48,7 @@ namespace Volo.Abp.Auditing
if (objectWithCreationTime.CreationTime == default)
{
- objectWithCreationTime.CreationTime = Clock.Now;
+ ObjectHelper.TrySetProperty(objectWithCreationTime, x => x.CreationTime, () => Clock.Now);
}
}
@@ -82,7 +82,7 @@ namespace Volo.Abp.Auditing
return;
}
- mayHaveCreatorObject.CreatorId = CurrentUser.Id;
+ ObjectHelper.TrySetProperty(mayHaveCreatorObject, x => x.CreatorId, () => CurrentUser.Id);
}
else if (targetObject is IMustHaveCreator mustHaveCreatorObject)
{
@@ -91,7 +91,7 @@ namespace Volo.Abp.Auditing
return;
}
- mustHaveCreatorObject.CreatorId = CurrentUser.Id.Value;
+ ObjectHelper.TrySetProperty(mustHaveCreatorObject, x => x.CreatorId, () => CurrentUser.Id.Value);
}
}
diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasCreationTime.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasCreationTime.cs
index 58e64cabef..07e9a7525b 100644
--- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasCreationTime.cs
+++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasCreationTime.cs
@@ -10,6 +10,6 @@ namespace Volo.Abp.Auditing
///
/// Creation time.
///
- DateTime CreationTime { get; set; }
+ DateTime CreationTime { get; }
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMayHaveCreator.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMayHaveCreator.cs
index 7960827d77..4fb4f9f49d 100644
--- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMayHaveCreator.cs
+++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMayHaveCreator.cs
@@ -9,7 +9,7 @@ namespace Volo.Abp.Auditing
/// Reference to the creator.
///
[CanBeNull]
- TCreator Creator { get; set; }
+ TCreator Creator { get; }
}
///
@@ -20,6 +20,6 @@ namespace Volo.Abp.Auditing
///
/// Id of the creator.
///
- Guid? CreatorId { get; set; }
+ Guid? CreatorId { get; }
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMustHaveCreator.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMustHaveCreator.cs
index 87671f97d6..14c6050dcd 100644
--- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMustHaveCreator.cs
+++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMustHaveCreator.cs
@@ -12,7 +12,7 @@ namespace Volo.Abp.Auditing
/// Reference to the creator.
///
[NotNull]
- TCreator Creator { get; set; }
+ TCreator Creator { get; }
}
///
@@ -23,6 +23,6 @@ namespace Volo.Abp.Auditing
///
/// Id of the creator.
///
- Guid CreatorId { get; set; }
+ Guid CreatorId { get; }
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs
new file mode 100644
index 0000000000..643c950b8a
--- /dev/null
+++ b/framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Volo.Abp
+{
+ public static class ObjectHelper
+ {
+ private static readonly ConcurrentDictionary CachedObjectProperties =
+ new ConcurrentDictionary();
+
+ public static void TrySetProperty(
+ TObject obj,
+ Expression> propertySelector,
+ Func valueFactory,
+ params Type[] ignoreAttributeTypes)
+ {
+ TrySetProperty(obj, propertySelector, x => valueFactory(), ignoreAttributeTypes);
+ }
+
+ public static void TrySetProperty(
+ TObject obj,
+ Expression> propertySelector,
+ Func valueFactory,
+ params Type[] ignoreAttributeTypes)
+ {
+ var property = CachedObjectProperties.GetOrAdd(
+ $"{obj.GetType().FullName}-{propertySelector}{(ignoreAttributeTypes != null ? string.Join("-", ignoreAttributeTypes.Select(x => x.FullName)) : "")}", () =>
+ {
+ if (propertySelector.Body.NodeType != ExpressionType.MemberAccess)
+ {
+ return null;
+ }
+
+ var memberExpression = propertySelector.Body.As();
+
+ var propertyInfo = obj.GetType().GetProperties().FirstOrDefault(x => x.Name == memberExpression.Member.Name && x.DeclaringType == obj.GetType());
+ if (propertyInfo == null || propertyInfo.GetSetMethod(true) == null)
+ {
+ return null;
+ }
+
+ if (ignoreAttributeTypes != null && ignoreAttributeTypes.Any(ignoreAttribute => propertyInfo.IsDefined(ignoreAttribute, true)))
+ {
+ return null;
+ }
+
+ return propertyInfo;
+ });
+
+ property?.SetValue(obj, valueFactory(obj));
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedAggregateRootWithUser.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedAggregateRootWithUser.cs
index 477f8750fd..69e6961630 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedAggregateRootWithUser.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedAggregateRootWithUser.cs
@@ -12,7 +12,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
where TUser : IEntity
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
///
public virtual TUser LastModifier { get; set; }
@@ -28,7 +28,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
where TUser : IEntity
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
///
public virtual TUser LastModifier { get; set; }
@@ -44,4 +44,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedEntityWithUser.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedEntityWithUser.cs
index cc54209595..1aa12a17da 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedEntityWithUser.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedEntityWithUser.cs
@@ -12,7 +12,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
where TUser : IEntity
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
///
public virtual TUser LastModifier { get; set; }
@@ -28,7 +28,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
where TUser : IEntity
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
///
public virtual TUser LastModifier { get; set; }
@@ -44,4 +44,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRoot.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRoot.cs
index 084c907606..4e42738b85 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRoot.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRoot.cs
@@ -10,10 +10,10 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedAggregateRoot : AggregateRoot, ICreationAuditedObject
{
///
- public virtual DateTime CreationTime { get; set; }
+ public virtual DateTime CreationTime { get; protected set; }
///
- public virtual Guid? CreatorId { get; set; }
+ public virtual Guid? CreatorId { get; protected set; }
}
///
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRootWithUser.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRootWithUser.cs
index 7d491d7be1..f576ba8452 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRootWithUser.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRootWithUser.cs
@@ -11,7 +11,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedAggregateRootWithUser : CreationAuditedAggregateRoot, ICreationAuditedObject
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
}
///
@@ -23,7 +23,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedAggregateRootWithUser : CreationAuditedAggregateRoot, ICreationAuditedObject
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
protected CreationAuditedAggregateRootWithUser()
{
@@ -36,4 +36,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntity.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntity.cs
index 41802c78b7..d039318fc1 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntity.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntity.cs
@@ -10,10 +10,10 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedEntity : Entity, ICreationAuditedObject
{
///
- public virtual DateTime CreationTime { get; set; }
+ public virtual DateTime CreationTime { get; protected set; }
///
- public virtual Guid? CreatorId { get; set; }
+ public virtual Guid? CreatorId { get; protected set; }
}
///
@@ -24,10 +24,10 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedEntity : Entity, ICreationAuditedObject
{
///
- public virtual DateTime CreationTime { get; set; }
+ public virtual DateTime CreationTime { get; protected set; }
///
- public virtual Guid? CreatorId { get; set; }
+ public virtual Guid? CreatorId { get; protected set; }
protected CreationAuditedEntity()
{
@@ -40,4 +40,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntityWithUser.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntityWithUser.cs
index 45d844efa7..c193f9486c 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntityWithUser.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntityWithUser.cs
@@ -11,7 +11,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedEntityWithUser : CreationAuditedEntity, ICreationAuditedObject
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
}
///
@@ -23,7 +23,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedEntityWithUser : CreationAuditedEntity, ICreationAuditedObject
{
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
protected CreationAuditedEntityWithUser()
{
@@ -36,4 +36,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs
index c6bfefbb23..312c3abd51 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs
@@ -15,7 +15,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
///
public virtual TUser LastModifier { get; set; }
@@ -34,7 +34,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
///
public virtual TUser LastModifier { get; set; }
@@ -50,4 +50,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedEntityWithUser.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedEntityWithUser.cs
index f7ec2b672f..1ce198304d 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedEntityWithUser.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedEntityWithUser.cs
@@ -15,7 +15,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
///
- public virtual TUser Creator { get; set; }
+ public virtual TUser Creator { get; protected set; }
///
public virtual TUser LastModifier { get; set; }
@@ -34,8 +34,8 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
///
- public virtual TUser Creator { get; set; }
-
+ public virtual TUser Creator { get; protected set; }
+
///
public virtual TUser LastModifier { get; set; }
@@ -50,4 +50,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs
index 65f2992257..0175498c9f 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs
@@ -13,11 +13,8 @@ namespace Volo.Abp.Domain.Entities
///
/// Some helper methods for entities.
///
- public static class EntityHelper
+ public static partial class EntityHelper
{
- private static readonly ConcurrentDictionary CachedIdProperties =
- new ConcurrentDictionary();
-
public static bool EntityEquals(IEntity entity1, IEntity entity2)
{
if (entity1 == null || entity2 == null)
@@ -77,7 +74,7 @@ namespace Volo.Abp.Domain.Entities
{
var entity1Key = entity1Keys[i];
var entity2Key = entity2Keys[i];
-
+
if (entity1Key == null)
{
if (entity2Key == null)
@@ -89,13 +86,13 @@ namespace Volo.Abp.Domain.Entities
//entity2Key is not null!
return false;
}
-
+
if (entity2Key == null)
{
//entity1Key was not null!
return false;
}
-
+
if (TypeHelper.IsDefaultValue(entity1Key) && TypeHelper.IsDefaultValue(entity2Key))
{
return false;
@@ -241,30 +238,13 @@ namespace Volo.Abp.Domain.Entities
Func idFactory,
bool checkForDisableIdGenerationAttribute = false)
{
- var property = CachedIdProperties.GetOrAdd(
- $"{entity.GetType().FullName}-{checkForDisableIdGenerationAttribute}", () =>
- {
- var idProperty = entity
- .GetType()
- .GetProperties()
- .FirstOrDefault(x => x.Name == nameof(entity.Id) &&
- x.GetSetMethod(true) != null);
-
- if (idProperty == null)
- {
- return null;
- }
-
- if (checkForDisableIdGenerationAttribute &&
- idProperty.IsDefined(typeof(DisableIdGenerationAttribute), true))
- {
- return null;
- }
-
- return idProperty;
- });
-
- property?.SetValue(entity, idFactory());
+ ObjectHelper.TrySetProperty(
+ entity,
+ x => x.Id,
+ idFactory,
+ checkForDisableIdGenerationAttribute
+ ? new Type[] { typeof(DisableIdGenerationAttribute) }
+ : new Type[] { });
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs
new file mode 100644
index 0000000000..facefbe915
--- /dev/null
+++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs
@@ -0,0 +1,78 @@
+using System.Runtime.Serialization;
+using Shouldly;
+using Xunit;
+
+namespace Volo.Abp
+{
+ public class ObjectHelper_Tests
+ {
+ [Fact]
+ public void TrySetProperty_Test()
+ {
+ var testClass = new MyClass();
+
+ ObjectHelper.TrySetProperty(testClass, x => x.Name, () => "NewName");
+ testClass.Name.ShouldBe("NewName");
+
+ ObjectHelper.TrySetProperty(testClass, x => x.Name2, () => "NewName2");
+ testClass.Name2.ShouldBe("NewName2");
+
+ ObjectHelper.TrySetProperty(testClass, x => x.Name3, () => "NewName3");
+ testClass.Name3.ShouldBe("NewName3");
+
+ ObjectHelper.TrySetProperty(testClass, x => x.Name4, () => "NewName4");
+ testClass.Name4.ShouldBe("Name4"); // readonly
+
+ ObjectHelper.TrySetProperty(testClass, x => x.Name5, () => "NewName5", ignoreAttributeTypes: typeof(IgnoreDataMemberAttribute));
+ testClass.Name5.ShouldNotBe("NewName5"); // ignore by attribute
+
+ ObjectHelper.TrySetProperty(testClass, x => x.ChildClass.Name, () => "NewChildName");
+ testClass.ChildClass.Name.ShouldNotBe("NewChildName");
+
+ ObjectHelper.TrySetProperty(testClass.ChildClass, x => x.Name, () => "NewChildName");
+ testClass.ChildClass.Name.ShouldBe("NewChildName");
+
+ ObjectHelper.TrySetProperty(testClass.ChildClass, x => x, () => new MyChildClass
+ {
+ Name = "NewChildName"
+ });
+ testClass.ChildClass.Name.ShouldBe("NewChildName");
+ }
+
+ class MyClass
+ {
+ public string Name { get; set; }
+
+ public string Name2 { get; protected set; }
+
+ public string Name3 { get; private set; }
+
+ public string Name4 { get; }
+
+ [IgnoreDataMember]
+ public string Name5 { get; }
+
+ public MyChildClass ChildClass { get; set; }
+
+ public MyClass()
+ {
+ Name = "Name";
+ Name2 = "Name2";
+ Name3 = "Name3";
+ Name4 = "Name4";
+ Name5 = "Name5";
+ ChildClass = new MyChildClass();
+ }
+ }
+
+ class MyChildClass
+ {
+ public string Name { get; set; }
+
+ public MyChildClass()
+ {
+ Name = "Name";
+ }
+ }
+ }
+}