Browse Source

Merge pull request #2000 from abpframework/maliming/DataTimeValueConverters

Added DataTimeValueConverters function.
pull/2253/head
Halil İbrahim Kalkan 7 years ago
committed by GitHub
parent
commit
ffc0c1329e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  2. 17
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs
  3. 9
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs
  4. 9
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs
  5. 24
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs
  6. 9
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs
  7. 13
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs
  8. 6
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs
  9. 17
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs
  10. 73
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs

50
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
@ -18,10 +18,12 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EntityFrameworkCore.EntityHistory;
using Volo.Abp.EntityFrameworkCore.ValueConverters;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
using Volo.Abp.Threading;
using Volo.Abp.Timing;
namespace Volo.Abp.EntityFrameworkCore
{
@ -48,6 +50,8 @@ namespace Volo.Abp.EntityFrameworkCore
public IAuditingManager AuditingManager { get; set; }
public IClock Clock { get; set; }
public ILogger<AbpDbContext<TDbContext>> Logger { get; set; }
private static readonly MethodInfo ConfigureBasePropertiesMethodInfo
@ -57,6 +61,13 @@ namespace Volo.Abp.EntityFrameworkCore
BindingFlags.Instance | BindingFlags.NonPublic
);
private static readonly MethodInfo ConfigureValueConverterMethodInfo
= typeof(AbpDbContext<TDbContext>)
.GetMethod(
nameof(ConfigureValueConverter),
BindingFlags.Instance | BindingFlags.NonPublic
);
protected AbpDbContext(DbContextOptions<TDbContext> options)
: base(options)
{
@ -75,6 +86,10 @@ namespace Volo.Abp.EntityFrameworkCore
ConfigureBasePropertiesMethodInfo
.MakeGenericMethod(entityType.ClrType)
.Invoke(this, new object[] { modelBuilder, entityType });
ConfigureValueConverterMethodInfo
.MakeGenericMethod(entityType.ClrType)
.Invoke(this, new object[] { modelBuilder, entityType });
}
}
@ -488,6 +503,39 @@ namespace Volo.Abp.EntityFrameworkCore
}
}
protected virtual void ConfigureValueConverter<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
where TEntity : class
{
if (mutableEntityType.BaseType == null &&
!typeof(TEntity).IsDefined(typeof(DisableDateTimeNormalizationAttribute), true) &&
!typeof(TEntity).IsDefined(typeof(OwnedAttribute), true) &&
!mutableEntityType.IsOwned())
{
if (Clock == null || !Clock.SupportsMultipleTimezone)
{
return;
}
var dateTimeValueConverter = new AbpDateTimeValueConverter(Clock);
var dateTimePropertyInfos = typeof(TEntity).GetProperties()
.Where(property =>
(property.PropertyType == typeof(DateTime) ||
property.PropertyType == typeof(DateTime?)) &&
property.CanWrite &&
!property.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true)
).ToList();
dateTimePropertyInfos.ForEach(property =>
{
modelBuilder
.Entity<TEntity>()
.Property(property.Name)
.HasConversion(dateTimeValueConverter);
});
}
}
protected virtual bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType) where TEntity : class
{
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))

17
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs

@ -0,0 +1,17 @@
using System;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Volo.Abp.Timing;
namespace Volo.Abp.EntityFrameworkCore.ValueConverters
{
public class AbpDateTimeValueConverter : ValueConverter<DateTime?, DateTime?>
{
public AbpDateTimeValueConverter(IClock clock, [CanBeNull] ConverterMappingHints mappingHints = null)
: base(
x => x.HasValue ? clock.Normalize(x.Value) : x,
x => x.HasValue ? clock.Normalize(x.Value) : x, mappingHints)
{
}
}
}

9
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs

@ -1,4 +1,5 @@
using Microsoft.Data.Sqlite;
using System;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
@ -10,6 +11,7 @@ using Volo.Abp.Modularity;
using Volo.Abp.TestApp;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.TestApp.EntityFrameworkCore;
using Volo.Abp.Timing;
namespace Volo.Abp.EntityFrameworkCore
{
@ -41,6 +43,8 @@ namespace Volo.Abp.EntityFrameworkCore
abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection);
});
});
Configure<AbpClockOptions>(options => options.Kind = DateTimeKind.Utc);
}
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
@ -56,6 +60,9 @@ namespace Volo.Abp.EntityFrameworkCore
using (var context = new TestMigrationsDbContext(new DbContextOptionsBuilder<TestMigrationsDbContext>().UseSqlite(connection).Options))
{
context.GetService<IRelationalDatabaseCreator>().CreateTables();
context.Database.ExecuteSqlRaw(
@"CREATE VIEW View_PersonView AS
SELECT Name, CreationTime, Birthday, LastActive FROM People");
}
return connection;

9
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs

@ -0,0 +1,9 @@
using Volo.Abp.TestApp.Testing;
namespace Volo.Abp.EntityFrameworkCore.ValueConverters
{
public class AbpDateTimeValueConverter_Tests : AbpDateTimeValueConverter_Tests<AbpEntityFrameworkCoreTestModule>
{
}
}

24
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.TestApp.Domain;
namespace Volo.Abp.TestApp.EntityFrameworkCore
{
public class PersonRepository : EfCoreRepository<TestAppDbContext, Person, Guid>, IPersonRepository
{
public PersonRepository(IDbContextProvider<TestAppDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<PersonView> GetViewAsync(string name)
{
return await DbContext.PersonView.Where(x => x.Name == name).FirstOrDefaultAsync();
}
}
}

9
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs

@ -11,6 +11,8 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore
public DbSet<City> Cities { get; set; }
public DbSet<PersonView> PersonView { get; set; }
public DbSet<ThirdDbContextDummyEntity> DummyEntities { get; set; }
public DbSet<EntityWithIntPk> EntityWithIntPks { get; set; }
@ -29,6 +31,13 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore
{
b.HasKey(p => new {p.PersonId, p.Number});
});
modelBuilder
.Entity<PersonView>(p =>
{
p.HasNoKey();
p.ToView("View_PersonView");
});
}
}
}

13
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.TestApp.Domain
{
public interface IPersonRepository : IBasicRepository<Person, Guid>
{
Task<PersonView> GetViewAsync(string name);
}
}

6
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.ObjectModel;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Timing;
namespace Volo.Abp.TestApp.Domain
{
@ -15,6 +16,11 @@ namespace Volo.Abp.TestApp.Domain
public virtual int Age { get; set; }
public virtual DateTime? Birthday { get; set; }
[DisableDateTimeNormalization]
public virtual DateTime? LastActive { get; set; }
public virtual Collection<Phone> Phones { get; set; }
private Person()

17
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs

@ -0,0 +1,17 @@
using System;
using Volo.Abp.Timing;
namespace Volo.Abp.TestApp.Domain
{
public class PersonView
{
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? Birthday { get; set; }
[DisableDateTimeNormalization]
public DateTime? LastActive { get; set; }
}
}

73
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs

@ -0,0 +1,73 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Modularity;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.Timing;
using Xunit;
namespace Volo.Abp.TestApp.Testing
{
public abstract class AbpDateTimeValueConverter_Tests<TStartupModule> : TestAppTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IPersonRepository _personRepository;
protected AbpDateTimeValueConverter_Tests()
{
_personRepository = GetRequiredService<IPersonRepository>();
}
[Fact]
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_Test()
{
var personId = Guid.Parse("4125582e-d100-4c27-aa84-e4de85830dca");
await _personRepository.InsertAsync(new Person(personId, "bob lee", 18)
{
Birthday = DateTime.Parse("2020-01-01 00:00:00"),
LastActive = DateTime.Parse("2020-01-01 00:00:00"),
}, true);
var person = await _personRepository.GetAsync(personId);
person.ShouldNotBeNull();
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.ShouldNotBeNull();
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
//LastActive DisableDateTimeNormalization
person.LastActive.ShouldNotBeNull();
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified);
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
}
[Fact]
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_View_Test()
{
var personName = "bob lee";
await _personRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 18)
{
Birthday = DateTime.Parse("2020-01-01 00:00:00"),
LastActive = DateTime.Parse("2020-01-01 00:00:00"),
}, true);
var person = await _personRepository.GetViewAsync(personName);
person.ShouldNotBeNull();
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.ShouldNotBeNull();
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
//LastActive DisableDateTimeNormalization
person.LastActive.ShouldNotBeNull();
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified);
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
}
}
}
Loading…
Cancel
Save