Browse Source

Make readonly for Creation audit properties of the entities.

Resolve #6020
pull/6051/head
maliming 6 years ago
parent
commit
2c8a68be22
  1. 6
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs
  2. 4
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasCreationTime.cs
  3. 6
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMayHaveCreator.cs
  4. 6
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMustHaveCreator.cs
  5. 57
      framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs
  6. 6
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedAggregateRootWithUser.cs
  7. 6
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedEntityWithUser.cs
  8. 4
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRoot.cs
  9. 6
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedAggregateRootWithUser.cs
  10. 10
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntity.cs
  11. 6
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/CreationAuditedEntityWithUser.cs
  12. 6
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs
  13. 8
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedEntityWithUser.cs
  14. 44
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs
  15. 78
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs

6
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);
}
}

4
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasCreationTime.cs

@ -10,6 +10,6 @@ namespace Volo.Abp.Auditing
/// <summary>
/// Creation time.
/// </summary>
DateTime CreationTime { get; set; }
DateTime CreationTime { get; }
}
}
}

6
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMayHaveCreator.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.Auditing
/// Reference to the creator.
/// </summary>
[CanBeNull]
TCreator Creator { get; set; }
TCreator Creator { get; }
}
/// <summary>
@ -20,6 +20,6 @@ namespace Volo.Abp.Auditing
/// <summary>
/// Id of the creator.
/// </summary>
Guid? CreatorId { get; set; }
Guid? CreatorId { get; }
}
}
}

6
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMustHaveCreator.cs

@ -12,7 +12,7 @@ namespace Volo.Abp.Auditing
/// Reference to the creator.
/// </summary>
[NotNull]
TCreator Creator { get; set; }
TCreator Creator { get; }
}
/// <summary>
@ -23,6 +23,6 @@ namespace Volo.Abp.Auditing
/// <summary>
/// Id of the creator.
/// </summary>
Guid CreatorId { get; set; }
Guid CreatorId { get; }
}
}
}

57
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<string, PropertyInfo> CachedObjectProperties =
new ConcurrentDictionary<string, PropertyInfo>();
public static void TrySetProperty<TObject, TValue>(
TObject obj,
Expression<Func<TObject, TValue>> propertySelector,
Func<TValue> valueFactory,
params Type[] ignoreAttributeTypes)
{
TrySetProperty(obj, propertySelector, x => valueFactory(), ignoreAttributeTypes);
}
public static void TrySetProperty<TObject, TValue>(
TObject obj,
Expression<Func<TObject, TValue>> propertySelector,
Func<TObject, TValue> 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<MemberExpression>();
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));
}
}
}

6
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<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -28,7 +28,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -44,4 +44,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
}
}

6
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<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -28,7 +28,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -44,4 +44,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
}
}

4
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
{
/// <inheritdoc />
public virtual DateTime CreationTime { get; set; }
public virtual DateTime CreationTime { get; protected set; }
/// <inheritdoc />
public virtual Guid? CreatorId { get; set; }
public virtual Guid? CreatorId { get; protected set; }
}
/// <summary>

6
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<TUser> : CreationAuditedAggregateRoot, ICreationAuditedObject<TUser>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
}
/// <summary>
@ -23,7 +23,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedAggregateRootWithUser<TKey, TUser> : CreationAuditedAggregateRoot<TKey>, ICreationAuditedObject<TUser>
{
/// <inheritdoc />
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
}
}
}
}

10
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
{
/// <inheritdoc />
public virtual DateTime CreationTime { get; set; }
public virtual DateTime CreationTime { get; protected set; }
/// <inheritdoc />
public virtual Guid? CreatorId { get; set; }
public virtual Guid? CreatorId { get; protected set; }
}
/// <summary>
@ -24,10 +24,10 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedEntity<TKey> : Entity<TKey>, ICreationAuditedObject
{
/// <inheritdoc />
public virtual DateTime CreationTime { get; set; }
public virtual DateTime CreationTime { get; protected set; }
/// <inheritdoc />
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
}
}
}
}

6
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<TUser> : CreationAuditedEntity, ICreationAuditedObject<TUser>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
}
/// <summary>
@ -23,7 +23,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public abstract class CreationAuditedEntityWithUser<TKey, TUser> : CreationAuditedEntity<TKey>, ICreationAuditedObject<TUser>
{
/// <inheritdoc />
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
}
}
}
}

6
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; }
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -34,7 +34,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -50,4 +50,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
}
}

8
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; }
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -34,8 +34,8 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
/// <inheritdoc />
public virtual TUser Creator { get; set; }
public virtual TUser Creator { get; protected set; }
/// <inheritdoc />
public virtual TUser LastModifier { get; set; }
@ -50,4 +50,4 @@ namespace Volo.Abp.Domain.Entities.Auditing
}
}
}
}

44
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs

@ -13,11 +13,8 @@ namespace Volo.Abp.Domain.Entities
/// <summary>
/// Some helper methods for entities.
/// </summary>
public static class EntityHelper
public static partial class EntityHelper
{
private static readonly ConcurrentDictionary<string, PropertyInfo> CachedIdProperties =
new ConcurrentDictionary<string, PropertyInfo>();
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<TKey> 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[] { });
}
}
}
}

78
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";
}
}
}
}
Loading…
Cancel
Save