Browse Source

Make `EntityHistoryHelper` compatible `ValueObject`.

Resolve #15674
pull/15688/head
maliming 4 years ago
parent
commit
b2a3d30ca2
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 7
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs
  2. 21
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  3. 6
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingTestModule.cs
  4. 41
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithValueObject.cs
  5. 14
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs
  6. 37
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs

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

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using JetBrains.Annotations;
using Volo.Abp.Domain.Values;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
@ -122,6 +123,12 @@ public static class EntityHelper
return typeof(IEntity).IsAssignableFrom(type);
}
public static bool IsValueObject([NotNull] Type type)
{
Check.NotNull(type, nameof(type));
return typeof(ValueObject).IsAssignableFrom(type);
}
public static void CheckEntity([NotNull] Type type)
{
Check.NotNull(type, nameof(type));

21
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

@ -12,6 +12,7 @@ using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Values;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
@ -92,7 +93,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
}
var entityId = GetEntityId(entity);
if (entityId == null && changeType != EntityChangeType.Created)
if (entityId == null && changeType != EntityChangeType.Created && !(entity is ValueObject))
{
return null;
}
@ -139,18 +140,24 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
protected virtual string GetEntityId(object entityAsObj)
{
if (!(entityAsObj is IEntity entity))
if ((entityAsObj is IEntity entity))
{
throw new AbpException($"Entities should implement the {typeof(IEntity).AssemblyQualifiedName} interface! Given entity does not implement it: {entityAsObj.GetType().AssemblyQualifiedName}");
var keys = entity.GetKeys();
if (keys.All(k => k == null))
{
return null;
}
return keys.JoinAsString(",");
}
var keys = entity.GetKeys();
if (keys.All(k => k == null))
if (entityAsObj is ValueObject)
{
return null;
}
return keys.JoinAsString(",");
throw new AbpException($"Entities should implement the {typeof(IEntity).AssemblyQualifiedName} interface or {typeof(ValueObject).AssemblyQualifiedName} class! " +
$"Given entity does not implement it: {entityAsObj.GetType().AssemblyQualifiedName}");
}
/// <summary>
@ -207,7 +214,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
var entityType = entityEntry.Metadata.ClrType;
if (!EntityHelper.IsEntity(entityType))
if (!EntityHelper.IsEntity(entityType) && !EntityHelper.IsValueObject(entityType))
{
return false;
}

6
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingTestModule.cs

@ -49,6 +49,12 @@ public class AbpAuditingTestModule : AbpModule
"AppEntityWithSoftDelete",
type => type == typeof(AppEntityWithSoftDelete))
);
options.EntityHistorySelectors.Add(
new NamedTypeSelector(
"AppEntityWithValueObject",
type => type == typeof(AppEntityWithValueObject) || type == typeof(AppEntityWithValueObjectAddress))
);
});
context.Services.AddType<Auditing_Tests.MyAuditedObject1>();

41
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithValueObject.cs

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Values;
namespace Volo.Abp.Auditing.App.Entities;
public class AppEntityWithValueObject : AggregateRoot<Guid>
{
protected AppEntityWithValueObject()
{
}
public AppEntityWithValueObject(Guid id, string name, AppEntityWithValueObjectAddress appEntityWithValueObjectAddress)
: base(id)
{
Name = name;
AppEntityWithValueObjectAddress = appEntityWithValueObjectAddress;
}
public string Name { get; set; }
public AppEntityWithValueObjectAddress AppEntityWithValueObjectAddress { get; set; }
}
public class AppEntityWithValueObjectAddress : ValueObject
{
public AppEntityWithValueObjectAddress(string country)
{
Country = country;
}
public string Country { get; set; }
protected override IEnumerable<object> GetAtomicValues()
{
yield return Country;
}
}

14
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Auditing.App.Entities;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace Volo.Abp.Auditing.App.EntityFrameworkCore;
@ -24,9 +25,22 @@ public class AbpAuditingTestDbContext : AbpDbContext<AbpAuditingTestDbContext>
public DbSet<AppEntityWithSoftDelete> AppEntityWithSoftDelete { get; set; }
public DbSet<AppEntityWithValueObject> AppEntityWithValueObject { get; set; }
public AbpAuditingTestDbContext(DbContextOptions<AbpAuditingTestDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<AppEntityWithValueObject>(b =>
{
b.ConfigureByConvention();
b.OwnsOne(v => v.AppEntityWithValueObjectAddress);
});
}
}

37
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NSubstitute;
@ -360,6 +361,42 @@ public class Auditing_Tests : AbpAuditingTestBase
#pragma warning restore 4014
}
[Fact]
public virtual async Task TestAsync()
{
var entityId = Guid.NewGuid();
var entity = new AppEntityWithValueObject(entityId, "test name", new AppEntityWithValueObjectAddress("USA"));
var repository = ServiceProvider.GetRequiredService<IBasicRepository<AppEntityWithValueObject, Guid>>();
await repository.InsertAsync(entity);
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity2 = await repository.GetAsync(entityId);
entity2.Name = "test name 2";
entity2.AppEntityWithValueObjectAddress = new AppEntityWithValueObjectAddress("England");
await repository.UpdateAsync(entity2);
await uow.CompleteAsync();
await scope.SaveAsync();
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 3 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Created &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithValueObject).FullName &&
x.EntityChanges[2].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[2].EntityTypeFullName == typeof(AppEntityWithValueObjectAddress).FullName));
#pragma warning restore 4014
}
}
public class Auditing_DisableLogActionInfo_Tests : Auditing_Tests

Loading…
Cancel
Save