From f1aad1d955217a627aea7cd3a6fb08168da6dcd5 Mon Sep 17 00:00:00 2001 From: Oguzhan Soykan Date: Tue, 29 May 2018 23:45:02 +0300 Subject: [PATCH 1/6] LazyLoading enabled & EFCore 2.1-rc1 package added to Stove.EntityFrameworkCore --- .../StoveEntityMaterializerSource.cs | 8 +++--- .../Stove.EntityFrameworkCore.csproj | 6 +++-- src/Stove.NHibernate/Stove.NHibernate.csproj | 2 +- src/Stove.WebApi/Stove.WebApi.csproj | 4 +-- src/Stove/Stove.csproj | 2 +- .../Stove.Demo.WebApiCore.csproj | 2 +- ...ve.EntityFrameworkCore.Dapper.Tests.csproj | 6 ++--- .../Domain/Blog.cs | 10 ++++---- .../Domain/Post.cs | 6 ++--- .../EntityFrameworkCoreTestBase.cs | 2 ++ .../Stove.EntityFrameworkCore.Tests.csproj | 8 +++--- ...tLoading_Tests.cs => LazyLoading_Tests.cs} | 25 ++++++++----------- .../Tests/Repository_Tests.cs | 6 ++--- .../Stove.Hangfire.Tests.csproj | 2 +- .../Stove.Mapster.Tests.csproj | 2 +- .../Stove.NHibernate.Tests.csproj | 2 +- test/Stove.NLog.Tests/Stove.NLog.Tests.csproj | 2 +- .../Stove.RabbitMQ.Tests.csproj | 2 +- .../Stove.Redis.Tests.csproj | 2 +- .../Stove.Serilog.Tests.csproj | 2 +- test/Stove.Tests/Stove.Tests.csproj | 2 +- 21 files changed, 51 insertions(+), 52 deletions(-) rename test/Stove.EntityFrameworkCore.Tests/Tests/{ExplicitLoading_Tests.cs => LazyLoading_Tests.cs} (60%) diff --git a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs index e83dfab..adff4f4 100644 --- a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs +++ b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs @@ -14,13 +14,13 @@ public class StoveEntityMaterializerSource : EntityMaterializerSource private static readonly MethodInfo NormalizeDateTimeMethod = typeof(StoveEntityMaterializerSource).GetTypeInfo().GetMethod(nameof(NormalizeDateTime), BindingFlags.Static | BindingFlags.NonPublic); private static readonly MethodInfo NormalizeNullableDateTimeMethod = typeof(StoveEntityMaterializerSource).GetTypeInfo().GetMethod(nameof(NormalizeNullableDateTime), BindingFlags.Static | BindingFlags.NonPublic); - public override Expression CreateReadValueExpression(Expression valueBuffer, Type type, int index, IProperty property = null) + public override Expression CreateReadValueExpression(Expression valueBuffer, Type type, int index, IPropertyBase propertyBase) { if (type == typeof(DateTime)) { return Expression.Call( NormalizeDateTimeMethod, - base.CreateReadValueExpression(valueBuffer, type, index, property) + base.CreateReadValueExpression(valueBuffer, type, index, propertyBase) ); } @@ -28,11 +28,11 @@ public override Expression CreateReadValueExpression(Expression valueBuffer, Typ { return Expression.Call( NormalizeNullableDateTimeMethod, - base.CreateReadValueExpression(valueBuffer, type, index, property) + base.CreateReadValueExpression(valueBuffer, type, index, propertyBase) ); } - return base.CreateReadValueExpression(valueBuffer, type, index, property); + return base.CreateReadValueExpression(valueBuffer, type, index, propertyBase); } private static DateTime NormalizeDateTime(DateTime value) diff --git a/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj b/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj index 256d1d6..aa882ca 100644 --- a/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj +++ b/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj @@ -19,8 +19,10 @@ - - + + + + diff --git a/src/Stove.NHibernate/Stove.NHibernate.csproj b/src/Stove.NHibernate/Stove.NHibernate.csproj index 0b36ed5..4dcde60 100644 --- a/src/Stove.NHibernate/Stove.NHibernate.csproj +++ b/src/Stove.NHibernate/Stove.NHibernate.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/Stove.WebApi/Stove.WebApi.csproj b/src/Stove.WebApi/Stove.WebApi.csproj index 76a1a1d..a93b7f5 100644 --- a/src/Stove.WebApi/Stove.WebApi.csproj +++ b/src/Stove.WebApi/Stove.WebApi.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/src/Stove/Stove.csproj b/src/Stove/Stove.csproj index 9377f90..af8a642 100644 --- a/src/Stove/Stove.csproj +++ b/src/Stove/Stove.csproj @@ -35,7 +35,7 @@ - + diff --git a/test/Stove.Demo.WebApiCore/Stove.Demo.WebApiCore.csproj b/test/Stove.Demo.WebApiCore/Stove.Demo.WebApiCore.csproj index dd56630..b380fb7 100644 --- a/test/Stove.Demo.WebApiCore/Stove.Demo.WebApiCore.csproj +++ b/test/Stove.Demo.WebApiCore/Stove.Demo.WebApiCore.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.0 diff --git a/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj b/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj index 2e30559..69b634f 100644 --- a/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj +++ b/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj @@ -5,9 +5,9 @@ - - - + + + diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs b/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs index 48c19fd..30519b8 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs @@ -34,20 +34,20 @@ public Blog(string name, string url) : this() ); } - public string Name { get; set; } + public virtual string Name { get; set; } - public string Url { get; protected set; } + public virtual string Url { get; protected set; } - public ICollection Posts { get; set; } + public virtual ICollection Posts { get; set; } - public DateTime CreationTime { get; set; } + public virtual DateTime CreationTime { get; set; } private void When(BlogUrlChangedEvent @event) { Url = @event.Url; } - public void ChangeUrl(string url) + public virtual void ChangeUrl(string url) { if (string.IsNullOrWhiteSpace(url)) { diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain/Post.cs b/test/Stove.EntityFrameworkCore.Tests/Domain/Post.cs index bf06bff..7fa75a0 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Domain/Post.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Domain/Post.cs @@ -8,11 +8,11 @@ namespace Stove.EntityFrameworkCore.Tests.Domain public class Post : AuditedEntity { [Required] - public Blog Blog { get; set; } + public virtual Blog Blog { get; set; } - public string Title { get; set; } + public virtual string Title { get; set; } - public string Body { get; set; } + public virtual string Body { get; set; } public Post() { diff --git a/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs b/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs index d033fb6..48ee993 100644 --- a/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs +++ b/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs @@ -27,6 +27,7 @@ protected EntityFrameworkCoreTestBase() : base(true) .UseStoveEventBus(); var bloggingDbContextBuilder = new DbContextOptionsBuilder(); + bloggingDbContextBuilder.UseLazyLoadingProxies(); bloggingDbContextBuilder.ReplaceService(); @@ -42,6 +43,7 @@ protected EntityFrameworkCoreTestBase() : base(true) var supportDbContextBuilder = new DbContextOptionsBuilder(); + supportDbContextBuilder.UseLazyLoadingProxies(); supportDbContextBuilder.ReplaceService(); diff --git a/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj b/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj index 578eb58..a686c5d 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj +++ b/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj @@ -5,13 +5,13 @@ - - + + - - + + diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/ExplicitLoading_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/LazyLoading_Tests.cs similarity index 60% rename from test/Stove.EntityFrameworkCore.Tests/Tests/ExplicitLoading_Tests.cs rename to test/Stove.EntityFrameworkCore.Tests/Tests/LazyLoading_Tests.cs index 64b7261..a12dd35 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/ExplicitLoading_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/LazyLoading_Tests.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Text; using System.Threading.Tasks; using Shouldly; @@ -11,30 +13,28 @@ namespace Stove.EntityFrameworkCore.Tests.Tests { - public class ExplicitLoading_Tests : EntityFrameworkCoreTestBase + public class LazyLoading_Tests : EntityFrameworkCoreTestBase { private readonly IRepository _blogRepository; private readonly IRepository _postRepository; - public ExplicitLoading_Tests() + public LazyLoading_Tests() { - Building(builder => { }).Ok(); + Building(builder => { }).Ok(); - _blogRepository = The>(); + _blogRepository = The>(); _postRepository = The>(); } [Fact] - public async Task Should_Explicitly_Load_Collections() + public async Task Should_Lazy_Load_Collections() { using (var uow = The().Begin()) { var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); - blog.ShouldNotBeNull(); - blog.Posts.ShouldBeNull(); //Because EF core does not have lazy loading yet! - await _blogRepository.EnsureCollectionLoadedAsync(blog, b => b.Posts); - blog.Posts.ShouldNotBeNull(); //Now loaded it! + blog.ShouldNotBeNull(); + blog.Posts.ShouldNotBeNull(); blog.Posts.Count.ShouldBeGreaterThan(0); await uow.CompleteAsync(); @@ -42,16 +42,13 @@ public async Task Should_Explicitly_Load_Collections() } [Fact] - public async Task Should_Explicitly_Load_Properties() + public async Task Should_Lazy_Load_Properties() { using (var uow = The().Begin()) { var post = await _postRepository.FirstOrDefaultAsync(b => b.Title == "test-post-1-title"); post.ShouldNotBeNull(); - post.Blog.ShouldBeNull(); //Because EF core does not have lazy loading yet! - - await _postRepository.EnsurePropertyLoadedAsync(post, p => p.Blog); - post.Blog.ShouldNotBeNull(); //Now loaded it! + post.Blog.ShouldNotBeNull(); post.Blog.Name.ShouldBe("test-blog-1"); await uow.CompleteAsync(); diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs index 053e682..476143d 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs @@ -72,15 +72,13 @@ await UsingDbContextAsync(async context => } [Fact] - public async Task Should_Not_Include_Navigation_Properties_If_Not_Requested() + public async Task Should_Include_Navigation_Properties_Because_It_Is_Lazy_Loaded() { - //EF Core does not support lazy loading yet, so navigation properties will not be loaded if not included - using (IUnitOfWorkCompleteHandle uow = _uowManager.Begin()) { Post post = await _postRepository.GetAll().FirstAsync(); - post.Blog.ShouldBeNull(); + post.Blog.ShouldNotBeNull(); await uow.CompleteAsync(); } diff --git a/test/Stove.Hangfire.Tests/Stove.Hangfire.Tests.csproj b/test/Stove.Hangfire.Tests/Stove.Hangfire.Tests.csproj index 2c4fa52..b8c4274 100644 --- a/test/Stove.Hangfire.Tests/Stove.Hangfire.Tests.csproj +++ b/test/Stove.Hangfire.Tests/Stove.Hangfire.Tests.csproj @@ -22,7 +22,7 @@ - + diff --git a/test/Stove.Mapster.Tests/Stove.Mapster.Tests.csproj b/test/Stove.Mapster.Tests/Stove.Mapster.Tests.csproj index 6dc6e24..d34edce 100644 --- a/test/Stove.Mapster.Tests/Stove.Mapster.Tests.csproj +++ b/test/Stove.Mapster.Tests/Stove.Mapster.Tests.csproj @@ -18,7 +18,7 @@ - + diff --git a/test/Stove.NHibernate.Tests/Stove.NHibernate.Tests.csproj b/test/Stove.NHibernate.Tests/Stove.NHibernate.Tests.csproj index 8238651..e8b45f6 100644 --- a/test/Stove.NHibernate.Tests/Stove.NHibernate.Tests.csproj +++ b/test/Stove.NHibernate.Tests/Stove.NHibernate.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/test/Stove.NLog.Tests/Stove.NLog.Tests.csproj b/test/Stove.NLog.Tests/Stove.NLog.Tests.csproj index 6cc5ed9..42aecb3 100644 --- a/test/Stove.NLog.Tests/Stove.NLog.Tests.csproj +++ b/test/Stove.NLog.Tests/Stove.NLog.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/test/Stove.RabbitMQ.Tests/Stove.RabbitMQ.Tests.csproj b/test/Stove.RabbitMQ.Tests/Stove.RabbitMQ.Tests.csproj index 07a699a..d6484c4 100644 --- a/test/Stove.RabbitMQ.Tests/Stove.RabbitMQ.Tests.csproj +++ b/test/Stove.RabbitMQ.Tests/Stove.RabbitMQ.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/Stove.Redis.Tests/Stove.Redis.Tests.csproj b/test/Stove.Redis.Tests/Stove.Redis.Tests.csproj index 29d96de..702fe3c 100644 --- a/test/Stove.Redis.Tests/Stove.Redis.Tests.csproj +++ b/test/Stove.Redis.Tests/Stove.Redis.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/test/Stove.Serilog.Tests/Stove.Serilog.Tests.csproj b/test/Stove.Serilog.Tests/Stove.Serilog.Tests.csproj index c1a95af..3bdb4e0 100644 --- a/test/Stove.Serilog.Tests/Stove.Serilog.Tests.csproj +++ b/test/Stove.Serilog.Tests/Stove.Serilog.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/test/Stove.Tests/Stove.Tests.csproj b/test/Stove.Tests/Stove.Tests.csproj index 59bf277..cae5889 100644 --- a/test/Stove.Tests/Stove.Tests.csproj +++ b/test/Stove.Tests/Stove.Tests.csproj @@ -12,7 +12,7 @@ - + From 2e49580828350e7654608a1def7a870114ecda39 Mon Sep 17 00:00:00 2001 From: Oguzhan Soykan Date: Wed, 30 May 2018 00:00:09 +0300 Subject: [PATCH 2/6] Explicit Loading removed #144 --- ...CoreRepositoryBase{TEntity,TPrimaryKey}.cs | 1 - .../Repositories/ISupportsExplicitLoading.cs | 26 ------ .../Repositories/RepositoryExtensions.cs | 80 ------------------- 3 files changed, 107 deletions(-) delete mode 100644 src/Stove/Domain/Repositories/ISupportsExplicitLoading.cs delete mode 100644 src/Stove/Domain/Repositories/RepositoryExtensions.cs diff --git a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Repositories/EfCoreRepositoryBase{TEntity,TPrimaryKey}.cs b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Repositories/EfCoreRepositoryBase{TEntity,TPrimaryKey}.cs index e7723cf..046fc1f 100644 --- a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Repositories/EfCoreRepositoryBase{TEntity,TPrimaryKey}.cs +++ b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Repositories/EfCoreRepositoryBase{TEntity,TPrimaryKey}.cs @@ -25,7 +25,6 @@ namespace Stove.EntityFrameworkCore.Repositories /// Primary key of the entity public class EfCoreRepositoryBase : StoveRepositoryBase, - ISupportsExplicitLoading, IRepositoryWithDbContext where TEntity : class, IEntity where TDbContext : DbContext diff --git a/src/Stove/Domain/Repositories/ISupportsExplicitLoading.cs b/src/Stove/Domain/Repositories/ISupportsExplicitLoading.cs deleted file mode 100644 index d853433..0000000 --- a/src/Stove/Domain/Repositories/ISupportsExplicitLoading.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Threading; -using System.Threading.Tasks; - -using Stove.Domain.Entities; - -namespace Stove.Domain.Repositories -{ - public interface ISupportsExplicitLoading - where TEntity : class, IEntity - { - Task EnsureCollectionLoadedAsync( - TEntity entity, - Expression>> propertyExpression, - CancellationToken cancellationToken) - where TProperty : class; - - Task EnsurePropertyLoadedAsync( - TEntity entity, - Expression> propertyExpression, - CancellationToken cancellationToken) - where TProperty : class; - } -} diff --git a/src/Stove/Domain/Repositories/RepositoryExtensions.cs b/src/Stove/Domain/Repositories/RepositoryExtensions.cs deleted file mode 100644 index 1f7984f..0000000 --- a/src/Stove/Domain/Repositories/RepositoryExtensions.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Threading; -using System.Threading.Tasks; - -using Autofac.Extras.IocManager; - -using Stove.Domain.Entities; -using Stove.Reflection; -using Stove.Threading; - -namespace Stove.Domain.Repositories -{ - public static class RepositoryExtensions - { - public static async Task EnsureCollectionLoadedAsync( - this IRepository repository, - TEntity entity, - Expression>> propertyExpression, - CancellationToken cancellationToken = default(CancellationToken) - ) - where TEntity : class, IEntity - where TProperty : class - { - if (ProxyHelper.UnProxyOrSelf(repository) is ISupportsExplicitLoading repo) - { - await repo.EnsureCollectionLoadedAsync(entity, propertyExpression, cancellationToken); - } - } - - public static void EnsureCollectionLoaded( - this IRepository repository, - TEntity entity, - Expression>> propertyExpression - ) - where TEntity : class, IEntity - where TProperty : class - { - AsyncHelper.RunSync(() => repository.EnsureCollectionLoadedAsync(entity, propertyExpression)); - } - - public static async Task EnsurePropertyLoadedAsync( - this IRepository repository, - TEntity entity, - Expression> propertyExpression, - CancellationToken cancellationToken = default(CancellationToken) - ) - where TEntity : class, IEntity - where TProperty : class - { - if (ProxyHelper.UnProxyOrSelf(repository) is ISupportsExplicitLoading repo) - { - await repo.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken); - } - } - - public static void EnsurePropertyLoaded( - this IRepository repository, - TEntity entity, - Expression> propertyExpression - ) - where TEntity : class, IEntity - where TProperty : class - { - AsyncHelper.RunSync(() => repository.EnsurePropertyLoadedAsync(entity, propertyExpression)); - } - - public static IScopeResolver GetIocResolver(this IRepository repository) - where TEntity : class, IEntity - { - if (ProxyHelper.UnProxyOrSelf(repository) is StoveRepositoryBase repo) - { - return repo.ScopeResolver; - } - - throw new ArgumentException($"Given {nameof(repository)} is not inherited from {typeof(StoveRepositoryBase).AssemblyQualifiedName}"); - } - } -} From a4ff154d3b9a1952e457f262de1f5cdfef0d60cd Mon Sep 17 00:00:00 2001 From: Oguzhan Soykan Date: Wed, 30 May 2018 14:59:27 +0300 Subject: [PATCH 3/6] Move All ASpnetCore 2.0 packages to 2.1 --- src/Stove.Dapper/Stove.Dapper.csproj | 2 +- .../StoveEntityMaterializerSource.cs | 8 ++++---- .../Stove.EntityFrameworkCore.csproj | 5 +++-- src/Stove.NHibernate/Stove.NHibernate.csproj | 2 +- src/Stove.NLog/Stove.NLog.csproj | 2 +- src/Stove.WebApi/Stove.WebApi.csproj | 4 ++-- src/Stove/Stove.csproj | 10 +++++----- .../Stove.EntityFrameworkCore.Dapper.Tests.csproj | 4 ++-- .../Stove.EntityFrameworkCore.Tests.csproj | 6 +++--- 9 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/Stove.Dapper/Stove.Dapper.csproj b/src/Stove.Dapper/Stove.Dapper.csproj index 83e8cc7..352b84d 100644 --- a/src/Stove.Dapper/Stove.Dapper.csproj +++ b/src/Stove.Dapper/Stove.Dapper.csproj @@ -30,6 +30,6 @@ - + diff --git a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs index e83dfab..adff4f4 100644 --- a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs +++ b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/StoveEntityMaterializerSource.cs @@ -14,13 +14,13 @@ public class StoveEntityMaterializerSource : EntityMaterializerSource private static readonly MethodInfo NormalizeDateTimeMethod = typeof(StoveEntityMaterializerSource).GetTypeInfo().GetMethod(nameof(NormalizeDateTime), BindingFlags.Static | BindingFlags.NonPublic); private static readonly MethodInfo NormalizeNullableDateTimeMethod = typeof(StoveEntityMaterializerSource).GetTypeInfo().GetMethod(nameof(NormalizeNullableDateTime), BindingFlags.Static | BindingFlags.NonPublic); - public override Expression CreateReadValueExpression(Expression valueBuffer, Type type, int index, IProperty property = null) + public override Expression CreateReadValueExpression(Expression valueBuffer, Type type, int index, IPropertyBase propertyBase) { if (type == typeof(DateTime)) { return Expression.Call( NormalizeDateTimeMethod, - base.CreateReadValueExpression(valueBuffer, type, index, property) + base.CreateReadValueExpression(valueBuffer, type, index, propertyBase) ); } @@ -28,11 +28,11 @@ public override Expression CreateReadValueExpression(Expression valueBuffer, Typ { return Expression.Call( NormalizeNullableDateTimeMethod, - base.CreateReadValueExpression(valueBuffer, type, index, property) + base.CreateReadValueExpression(valueBuffer, type, index, propertyBase) ); } - return base.CreateReadValueExpression(valueBuffer, type, index, property); + return base.CreateReadValueExpression(valueBuffer, type, index, propertyBase); } private static DateTime NormalizeDateTime(DateTime value) diff --git a/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj b/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj index 256d1d6..8f5f79b 100644 --- a/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj +++ b/src/Stove.EntityFrameworkCore/Stove.EntityFrameworkCore.csproj @@ -19,8 +19,9 @@ - - + + + diff --git a/src/Stove.NHibernate/Stove.NHibernate.csproj b/src/Stove.NHibernate/Stove.NHibernate.csproj index 0b36ed5..4dcde60 100644 --- a/src/Stove.NHibernate/Stove.NHibernate.csproj +++ b/src/Stove.NHibernate/Stove.NHibernate.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/Stove.NLog/Stove.NLog.csproj b/src/Stove.NLog/Stove.NLog.csproj index ecba741..1c2b025 100644 --- a/src/Stove.NLog/Stove.NLog.csproj +++ b/src/Stove.NLog/Stove.NLog.csproj @@ -27,6 +27,6 @@ - + diff --git a/src/Stove.WebApi/Stove.WebApi.csproj b/src/Stove.WebApi/Stove.WebApi.csproj index 76a1a1d..3ee4bb3 100644 --- a/src/Stove.WebApi/Stove.WebApi.csproj +++ b/src/Stove.WebApi/Stove.WebApi.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/src/Stove/Stove.csproj b/src/Stove/Stove.csproj index 9377f90..0678bca 100644 --- a/src/Stove/Stove.csproj +++ b/src/Stove/Stove.csproj @@ -26,16 +26,16 @@ - - + + - + - - + + diff --git a/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj b/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj index 2e30559..4659a30 100644 --- a/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj +++ b/test/Stove.EntityFrameworkCore.Dapper.Tests/Stove.EntityFrameworkCore.Dapper.Tests.csproj @@ -5,8 +5,8 @@ - - + + diff --git a/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj b/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj index 578eb58..e27d64f 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj +++ b/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj @@ -5,13 +5,13 @@ - + - - + + From 8fa514dc88b0993eb69a080f0e9b91839b8097df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Caner=20Pat=C4=B1r?= Date: Wed, 30 May 2018 20:27:21 +0300 Subject: [PATCH 4/6] #144 Dynamic filtering, domain and dapper tests are implemented EF Core 2.1 integration --- .../Domain/Blog.cs | 4 +- .../Domain_Product/Events/VariantAdded.cs | 20 ++ .../Events/VariantValueAdded.cs | 17 ++ .../Domain_Product/Product.cs | 62 +++++ .../Domain_Product/ProductVariant.cs | 38 +++ .../Domain_Product/VariantValue.cs | 21 ++ .../Ef/ProductDbContext.cs | 19 ++ .../EntityFrameworkCoreTestBase.cs | 244 +++++++++--------- .../Stove.EntityFrameworkCore.Tests.csproj | 1 + .../Domain_ReadModel_With_Dapper_Tests.cs | 63 +++++ .../Tests/Domain_Tests.cs | 80 ++++++ .../Tests/DynamicFiltering_Tests.cs | 87 +++++++ .../Tests/Repository_Tests.cs | 6 +- .../Tests/Transaction_Tests.cs | 4 +- 14 files changed, 533 insertions(+), 133 deletions(-) create mode 100644 test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantAdded.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantValueAdded.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Domain_Product/Product.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Domain_Product/ProductVariant.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Domain_Product/VariantValue.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Ef/ProductDbContext.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Tests/Domain_Tests.cs create mode 100644 test/Stove.EntityFrameworkCore.Tests/Tests/DynamicFiltering_Tests.cs diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs b/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs index 30519b8..4051329 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Domain/Blog.cs @@ -7,7 +7,7 @@ namespace Stove.EntityFrameworkCore.Tests.Domain { - public class Blog : AggregateRoot, IHasCreationTime + public class Blog : AggregateRoot, IHasCreationTime, ISoftDelete { public Blog() { @@ -41,6 +41,8 @@ public Blog(string name, string url) : this() public virtual ICollection Posts { get; set; } public virtual DateTime CreationTime { get; set; } + + public bool IsDeleted { get; set; } private void When(BlogUrlChangedEvent @event) { diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantAdded.cs b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantAdded.cs new file mode 100644 index 0000000..497bdfc --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantAdded.cs @@ -0,0 +1,20 @@ +using Stove.Events.Bus; + +namespace Stove.EntityFrameworkCore.Tests.Domain_Product.Events +{ + public class VariantAdded : Event + { + public int ProductId { get; } + + public string Barcode { get; set; } + + public string VariantName { get; set; } + + public VariantAdded(int productId, string barcode, string variantName) + { + ProductId = productId; + Barcode = barcode; + VariantName = variantName; + } + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantValueAdded.cs b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantValueAdded.cs new file mode 100644 index 0000000..58fbc11 --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Events/VariantValueAdded.cs @@ -0,0 +1,17 @@ +using Stove.Events.Bus; + +namespace Stove.EntityFrameworkCore.Tests.Domain_Product.Events +{ + public class VariantValueAdded : Event + { + public int Id { get; } + + public string Value { get; } + + public VariantValueAdded(int id, string value) + { + Id = id; + Value = value; + } + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Product.cs b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Product.cs new file mode 100644 index 0000000..76a9c5f --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/Product.cs @@ -0,0 +1,62 @@ +using Stove.Domain.Entities; +using Stove.EntityFrameworkCore.Tests.Domain_Product.Events; +using System; +using System.Collections.Generic; + +namespace Stove.EntityFrameworkCore.Tests.Domain_Product +{ + public class Product : AggregateRoot + { + public virtual string Title { get; protected set; } + + public virtual string ProductCode { get; protected set; } + + public virtual ICollection Variants { get; protected set; } + + protected Product() + { + Register(When); + } + + public Product(string title, string productCode) : this() + { + Title = title; + ProductCode = productCode; + } + + public void AddVariant(string barcode, string variantName) + { + if (barcode == null) + { + throw new ArgumentNullException(nameof(barcode)); + } + + if (variantName == null) + { + throw new ArgumentNullException(nameof(variantName)); + } + + ApplyChange(new VariantAdded(Id, barcode, variantName)); + } + + public void AddVariantValue(ProductVariant variant, string variantValue) + { + if (variantValue == null) + { + throw new ArgumentNullException(nameof(variantValue)); + } + + var @event = new VariantValueAdded(variant.Id, variantValue); + variant.Route(@event); + ApplyChange(@event); + } + + private void When(VariantAdded @event) + { + var variant = new ProductVariant(this, @event.Barcode, @event.VariantName); + + Variants.Add(variant); + } + + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain_Product/ProductVariant.cs b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/ProductVariant.cs new file mode 100644 index 0000000..24291e6 --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/ProductVariant.cs @@ -0,0 +1,38 @@ +using Stove.Domain.Entities; +using Stove.EntityFrameworkCore.Tests.Domain_Product.Events; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Stove.EntityFrameworkCore.Tests.Domain_Product +{ + public class ProductVariant : Entity + { + [Required] + public virtual Product Product { get; protected set; } + + public virtual string Barcode { get; protected set; } + + public virtual string Name { get; protected set; } + + public virtual ICollection Values { get; protected set; } + + + protected ProductVariant() + { + Register(When); + } + + public ProductVariant(Product product, string barcode, string name) : this() + { + Product = product; + Barcode = barcode; + Name = name; + } + + private void When(VariantValueAdded @event) + { + Values.Add(new VariantValue(this, @event.Value)); + } + + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Domain_Product/VariantValue.cs b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/VariantValue.cs new file mode 100644 index 0000000..6d2efec --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Domain_Product/VariantValue.cs @@ -0,0 +1,21 @@ +using Stove.Domain.Entities; +using System.ComponentModel.DataAnnotations; + +namespace Stove.EntityFrameworkCore.Tests.Domain_Product +{ + public class VariantValue : Entity + { + [Required] + public virtual ProductVariant Variant { get; protected set; } + + public virtual string Value { get; protected set; } + + protected VariantValue() { } + + public VariantValue(ProductVariant variant, string value) + { + Variant = variant; + Value = value; + } + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Ef/ProductDbContext.cs b/test/Stove.EntityFrameworkCore.Tests/Ef/ProductDbContext.cs new file mode 100644 index 0000000..6edb1b0 --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Ef/ProductDbContext.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using Stove.EntityFrameworkCore.Tests.Domain_Product; + +namespace Stove.EntityFrameworkCore.Tests.Ef +{ + public class ProductDbContext : StoveDbContext + { + public DbSet Products { get; set; } + + public DbSet ProductVariants { get; set; } + + public DbSet VaraintValues { get; set; } + + public ProductDbContext(DbContextOptions options) + : base(options) + { + } + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs b/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs index 48ee993..b4282a9 100644 --- a/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs +++ b/test/Stove.EntityFrameworkCore.Tests/EntityFrameworkCoreTestBase.cs @@ -1,10 +1,10 @@ using System; using System.Threading.Tasks; - +using Autofac.Extras.IocManager; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Internal; - +using Stove.Dapper; using Stove.Domain.Repositories; using Stove.EntityFrameworkCore.Tests.Domain; using Stove.EntityFrameworkCore.Tests.Ef; @@ -14,129 +14,119 @@ namespace Stove.EntityFrameworkCore.Tests { - public abstract class EntityFrameworkCoreTestBase : ApplicationTestBase - { - protected EntityFrameworkCoreTestBase() : base(true) - { - Clock.Provider = ClockProviders.Utc; - - Building(builder => - { - builder - .UseStoveEntityFrameworkCore() - .UseStoveEventBus(); - - var bloggingDbContextBuilder = new DbContextOptionsBuilder(); - bloggingDbContextBuilder.UseLazyLoadingProxies(); - - bloggingDbContextBuilder.ReplaceService(); - - var bloggingDbContextInMemorySqlite = new SqliteConnection("Data Source=:memory:"); - bloggingDbContextBuilder.UseSqlite(bloggingDbContextInMemorySqlite); - - builder.RegisterServices(r => r.Register(ctx => bloggingDbContextBuilder.Options)); - - bloggingDbContextInMemorySqlite.Open(); - new BloggingDbContext(bloggingDbContextBuilder.Options).Database.EnsureCreated(); - - - - - var supportDbContextBuilder = new DbContextOptionsBuilder(); - supportDbContextBuilder.UseLazyLoadingProxies(); - - supportDbContextBuilder.ReplaceService(); - - var supportDbContextInMemorySqlite = new SqliteConnection("Data Source=:memory:"); - supportDbContextBuilder.UseSqlite(supportDbContextInMemorySqlite); - - builder.RegisterServices(r => r.Register(ctx => supportDbContextBuilder.Options)); - - supportDbContextInMemorySqlite.Open(); - new SupportDbContext(supportDbContextBuilder.Options).Database.EnsureCreated(); - - builder.RegisterServices(r => - { - r.Register, IPostRepository, PostRepository>(); - r.RegisterAssemblyByConvention(typeof(EntityFrameworkCoreTestBase).GetAssembly()); - }); - - }); - } - - protected override void PostBuild() - { - CreateInitialData(); - } - - private void CreateInitialData() - { - UsingDbContext( - context => - { - var blog1 = new Blog("test-blog-1", "http://testblog1.myblogs.com"); - - context.Blogs.Add(blog1); - - var post1 = new Post { Blog = blog1, Title = "test-post-1-title", Body = "test-post-1-body" }; - var post2 = new Post { Blog = blog1, Title = "test-post-2-title", Body = "test-post-2-body" }; - - context.Posts.AddRange(post1, post2); - }); - - using (var context = The()) - { - context.Tickets.AddRange( - new Ticket { EmailAddress = "john@stove.com", Message = "an active message" }, - new Ticket { EmailAddress = "david@stove.com", Message = "an inactive message", IsActive = false } - ); - - context.SaveChanges(); - } - } - - public void UsingDbContext(Action action) - { - using (var context = The()) - { - action(context); - context.SaveChanges(); - } - } - - public T UsingDbContext(Func func) - { - T result; - - using (var context = The()) - { - result = func(context); - context.SaveChanges(); - } - - return result; - } - - public async Task UsingDbContextAsync(Func action) - { - using (var context = The()) - { - await action(context); - await context.SaveChangesAsync(true); - } - } - - public async Task UsingDbContextAsync(Func> func) - { - T result; - - using (var context = The()) - { - result = await func(context); - context.SaveChanges(); - } - - return result; - } - } + public abstract class EntityFrameworkCoreTestBase : ApplicationTestBase + { + protected EntityFrameworkCoreTestBase() : base(true) + { + Clock.Provider = ClockProviders.Utc; + + Building(builder => + { + builder + .UseStoveEntityFrameworkCore() + .UseStoveEventBus() + .UseStoveDapper(); + + RegisterInMemoryDbContext(builder, opt => new BloggingDbContext(opt)); + RegisterInMemoryDbContext(builder, opt => new SupportDbContext(opt)); + + builder.RegisterServices(r => + { + r.Register, IPostRepository, PostRepository>(); + r.RegisterAssemblyByConvention(typeof(EntityFrameworkCoreTestBase).GetAssembly()); + }); + }); + } + + protected void RegisterInMemoryDbContext(IIocBuilder builder, Func, TDbContext> dbContextFactory) where TDbContext : StoveDbContext + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseLazyLoadingProxies(); + + optionsBuilder.ReplaceService(); + + var inMemorySqlLiteConnection = new SqliteConnection("Data Source=:memory:"); + optionsBuilder.UseSqlite(inMemorySqlLiteConnection); + + builder.RegisterServices(r => r.Register(ctx => optionsBuilder.Options)); + + inMemorySqlLiteConnection.Open(); + + dbContextFactory(optionsBuilder.Options).Database.EnsureCreated(); + } + + protected override void PostBuild() + { + CreateInitialData(); + } + + private void CreateInitialData() + { + UsingDbContext( + context => + { + var blog1 = new Blog("test-blog-1", "http://testblog1.myblogs.com"); + + context.Blogs.Add(blog1); + + var post1 = new Post { Blog = blog1, Title = "test-post-1-title", Body = "test-post-1-body" }; + var post2 = new Post { Blog = blog1, Title = "test-post-2-title", Body = "test-post-2-body" }; + + context.Posts.AddRange(post1, post2); + }); + + UsingDbContext( + context => + { + context.Tickets.AddRange( + new Ticket { EmailAddress = "john@stove.com", Message = "an active message" }, + new Ticket { EmailAddress = "david@stove.com", Message = "an inactive message", IsActive = false } + ); + }); + } + + public void UsingDbContext(Action action) where TDbContext : StoveDbContext + { + using (var context = The()) + { + action(context); + context.SaveChanges(); + } + } + + public T UsingDbContext(Func func) where TDbContext : StoveDbContext + { + T result; + + using (var context = The()) + { + result = func(context); + context.SaveChanges(); + } + + return result; + } + + public async Task UsingDbContextAsync(Func action) where TDbContext : StoveDbContext + { + using (var context = The()) + { + await action(context); + await context.SaveChangesAsync(true); + } + } + + public async Task UsingDbContextAsync(Func> func) where TDbContext : StoveDbContext + { + T result; + + using (var context = The()) + { + result = await func(context); + context.SaveChanges(); + } + + return result; + } + } } diff --git a/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj b/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj index 1aa3aba..5acf1df 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj +++ b/test/Stove.EntityFrameworkCore.Tests/Stove.EntityFrameworkCore.Tests.csproj @@ -15,6 +15,7 @@ + diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs new file mode 100644 index 0000000..e73a71e --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs @@ -0,0 +1,63 @@ +using Shouldly; +using Stove.Dapper.Repositories; +using Stove.Domain.Uow; +using Stove.EntityFrameworkCore.Tests.Domain_Product; +using Stove.EntityFrameworkCore.Tests.Ef; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace Stove.EntityFrameworkCore.Tests.Tests +{ + public class Domain_ReadModel_With_Dapper_Tests : EntityFrameworkCoreTestBase + { + private readonly IDapperRepository _productDapperRepository; + + public Domain_ReadModel_With_Dapper_Tests() + { + Building(builder => + { + RegisterInMemoryDbContext(builder, opt => new ProductDbContext(opt)); + }).Ok(); + + UsingDbContext(context => + { + context.Products.Add(new Product("Adidas Awesome Sneaker", "adidas_code_1")); + context.Products.Add(new Product("Adidas Awesome Sweatshirt", "adidas_code_2")); + }); + + _productDapperRepository = The>(); + } + + [Fact] + public async Task Should_Get_All_Products() + { + using (var uow = The().Begin()) + { + IEnumerable products = await _productDapperRepository.QueryAsync("SELECT * FROM Products ORDER BY Id"); + + products.Count().ShouldBe(2); + + products.ElementAt(0).ProductCode.ShouldBe("adidas_code_1"); + products.ElementAt(1).ProductCode.ShouldBe("adidas_code_2"); + + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task Should_Get_Product_With_Filter() + { + using (var uow = The().Begin()) + { + IEnumerable products = await _productDapperRepository.QueryAsync("SELECT * FROM Products WHERE Title=@Title", new { Title = "Adidas Awesome Sneaker" }); + + products.Count().ShouldBe(1); + products.First().ProductCode.ShouldBe("adidas_code_1"); + + await uow.CompleteAsync(); + } + } + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_Tests.cs new file mode 100644 index 0000000..321d4b9 --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_Tests.cs @@ -0,0 +1,80 @@ +using Stove.Domain.Repositories; +using Stove.Domain.Uow; +using Stove.EntityFrameworkCore.Tests.Domain_Product; +using Stove.EntityFrameworkCore.Tests.Ef; +using System.Threading.Tasks; +using Xunit; +using Shouldly; +using System.Linq; +using Microsoft.EntityFrameworkCore; + +namespace Stove.EntityFrameworkCore.Tests.Tests +{ + public class Domain_Tests : EntityFrameworkCoreTestBase + { + private readonly IRepository _productRepository; + private readonly IRepository _productVariantRepository; + + public Domain_Tests() + { + Building(builder => + { + RegisterInMemoryDbContext(builder, opt => new ProductDbContext(opt)); + }).Ok(); + + UsingDbContext(context => + { + Product adidasAwesomeSneaker = context.Products.Add(new Product("Adidas Awesome Sneaker", "adidas_code_1")).Entity; + ProductVariant adidasSneakerXL = context.ProductVariants.Add(new ProductVariant(adidasAwesomeSneaker, "adidas_barcode_1", "Number")).Entity; + + context.VaraintValues.Add(new VariantValue(adidasSneakerXL, "40")); + context.VaraintValues.Add(new VariantValue(adidasSneakerXL, "42")); + context.VaraintValues.Add(new VariantValue(adidasSneakerXL, "43")); + }); + + _productRepository = The>(); + _productVariantRepository = The>(); + } + + [Fact] + public async Task Add_Variant_to_Product() + { + using (var uow = The().Begin()) + { + Product product = await _productRepository.FirstOrDefaultAsync(x => x.Title == "Adidas Awesome Sneaker"); + product.AddVariant("barcode_1", "43"); + + await uow.CompleteAsync(); + } + + await UsingDbContextAsync(async context => + { + ProductVariant productVariant = await context.ProductVariants.FirstOrDefaultAsync(v => v.Barcode == "barcode_1"); + productVariant.ShouldNotBeNull(); + productVariant.Product.Title.ShouldBe("Adidas Awesome Sneaker"); + }); + } + + [Fact] + public async Task Add_Value_to_Variant() + { + using (var uow = The().Begin()) + { + Product product = await _productRepository.FirstOrDefaultAsync(x => x.Title == "Adidas Awesome Sneaker"); + ProductVariant variant = await _productVariantRepository.FirstOrDefaultAsync(v => v.Barcode == "adidas_barcode_1"); + + product.AddVariantValue(variant, "46"); + + await uow.CompleteAsync(); + } + + await UsingDbContextAsync(async context => + { + ProductVariant productVariant = await context.ProductVariants.FirstOrDefaultAsync(v => v.Barcode == "adidas_barcode_1"); + productVariant.Values.Count.ShouldBe(4); + productVariant.Values.Any(sv => sv.Value == "46").ShouldBe(true); + }); + } + + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/DynamicFiltering_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/DynamicFiltering_Tests.cs new file mode 100644 index 0000000..613f8d4 --- /dev/null +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/DynamicFiltering_Tests.cs @@ -0,0 +1,87 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using Stove.Domain.Repositories; +using Stove.Domain.Uow; +using Stove.EntityFrameworkCore.Tests.Domain; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace Stove.EntityFrameworkCore.Tests.Tests +{ + public class DynamicFiltering_Tests : EntityFrameworkCoreTestBase + { + private readonly IRepository _blogRepository; + + public DynamicFiltering_Tests() + { + Building(builder => { }).Ok(); + + _blogRepository = The>(); + } + + [Fact] + public async Task Should_Filter_Soft_Deleted_Record() + { + using (var uow = The().Begin()) + { + var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); + + await _blogRepository.DeleteAsync(blog); + + await uow.CompleteAsync(); + } + + using (var uow = The().Begin()) + { + var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); + + blog.ShouldBeNull(); + } + } + + [Fact] + public async Task Should_Filter_Soft_Deleted_For_Lazy_Loaded_Child_Collection() + { + using (var uow = The().Begin()) + { + var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); + + blog.Posts.Count.ShouldBe(2); + + blog.Posts.Remove(blog.Posts.First()); + + await uow.CompleteAsync(); + } + + using (var uow = The().Begin()) + { + var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); + + blog.Posts.Count.ShouldBe(1); + } + } + + [Fact] + public async Task Should_Filter_Soft_Deleted_For_Eager_Loaded_Child_Collection() + { + using (var uow = The().Begin()) + { + var blog = await _blogRepository.GetAll().Where(b => b.Name == "test-blog-1").Include(b => b.Posts).FirstOrDefaultAsync(); + + blog.Posts.Count.ShouldBe(2); + + blog.Posts.Remove(blog.Posts.First()); + + await uow.CompleteAsync(); + } + + using (var uow = The().Begin()) + { + var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); + + blog.Posts.Count.ShouldBe(1); + } + } + } +} diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs index 476143d..5020bdd 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Repository_Tests.cs @@ -11,8 +11,8 @@ using Stove.Domain.Uow; using Stove.EntityFrameworkCore.Tests.Domain; using Stove.EntityFrameworkCore.Tests.Domain.Events; -using Stove.Events.Bus; -using Stove.Events.Bus.Entities; +using Stove.EntityFrameworkCore.Tests.Ef; +using Stove.Events.Bus; using Xunit; @@ -64,7 +64,7 @@ public async Task Should_Automatically_Save_Changes_On_Uow() //Assert - await UsingDbContextAsync(async context => + await UsingDbContextAsync(async context => { Blog blog1 = await context.Blogs.SingleAsync(b => b.Id == blog1Id); blog1.Name.ShouldBe("test-blog-1-updated"); diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs index 9104aa1..88fe4e5 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs @@ -8,7 +8,7 @@ using Stove.Domain.Repositories; using Stove.Domain.Uow; using Stove.EntityFrameworkCore.Tests.Domain; - +using Stove.EntityFrameworkCore.Tests.Ef; using Xunit; namespace Stove.EntityFrameworkCore.Tests.Tests @@ -50,7 +50,7 @@ await _blogRepository.InsertAsync( } - await UsingDbContextAsync(async context => + await UsingDbContextAsync(async context => { var blog = await context.Blogs.FirstOrDefaultAsync(b => b.Name == blogName); blog.ShouldNotBeNull(); From 514e5e6e34468fbfa95398236901d1901e2ca7e9 Mon Sep 17 00:00:00 2001 From: osoykan Date: Wed, 30 May 2018 22:28:19 +0300 Subject: [PATCH 5/6] some cleanups --- .../Uow/EfCoreUnitOfWork.cs | 15 +-- .../Domain_ReadModel_With_Dapper_Tests.cs | 111 +++++++++--------- .../Tests/LazyLoading_Tests.cs | 86 +++++++------- .../Tests/Parallel_Querying_Tests.cs | 2 +- .../Tests/Transaction_Tests.cs | 4 +- 5 files changed, 103 insertions(+), 115 deletions(-) diff --git a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Uow/EfCoreUnitOfWork.cs b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Uow/EfCoreUnitOfWork.cs index f239c29..19ac422 100644 --- a/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Uow/EfCoreUnitOfWork.cs +++ b/src/Stove.EntityFrameworkCore/EntityFrameworkCore/Uow/EfCoreUnitOfWork.cs @@ -167,18 +167,5 @@ protected virtual void Release(DbContext dbContext) { dbContext.Dispose(); } - - //private static void ObjectContext_ObjectMaterialized(DbContext dbContext, ObjectMaterializedEventArgs e) - //{ - // dbContext.Configuration.AutoDetectChangesEnabled = true; - - // dbContext.Entry(e.Entity).State = previousState; - - // DateTimePropertyInfoHelper.NormalizeDatePropertyKinds(e.Entity, entityType); - // var previousState = dbContext.Entry(e.Entity).State; - - // dbContext.Configuration.AutoDetectChangesEnabled = false; - // var entityType = ObjectContext.GetObjectType(e.Entity.GetType()); - //} - } + } } diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs index e73a71e..24ee896 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Domain_ReadModel_With_Dapper_Tests.cs @@ -1,63 +1,66 @@ -using Shouldly; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Shouldly; + using Stove.Dapper.Repositories; using Stove.Domain.Uow; using Stove.EntityFrameworkCore.Tests.Domain_Product; using Stove.EntityFrameworkCore.Tests.Ef; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; + using Xunit; namespace Stove.EntityFrameworkCore.Tests.Tests { - public class Domain_ReadModel_With_Dapper_Tests : EntityFrameworkCoreTestBase - { - private readonly IDapperRepository _productDapperRepository; - - public Domain_ReadModel_With_Dapper_Tests() - { - Building(builder => - { - RegisterInMemoryDbContext(builder, opt => new ProductDbContext(opt)); - }).Ok(); - - UsingDbContext(context => - { - context.Products.Add(new Product("Adidas Awesome Sneaker", "adidas_code_1")); - context.Products.Add(new Product("Adidas Awesome Sweatshirt", "adidas_code_2")); - }); - - _productDapperRepository = The>(); - } - - [Fact] - public async Task Should_Get_All_Products() - { - using (var uow = The().Begin()) - { - IEnumerable products = await _productDapperRepository.QueryAsync("SELECT * FROM Products ORDER BY Id"); - - products.Count().ShouldBe(2); - - products.ElementAt(0).ProductCode.ShouldBe("adidas_code_1"); - products.ElementAt(1).ProductCode.ShouldBe("adidas_code_2"); - - await uow.CompleteAsync(); - } - } - - [Fact] - public async Task Should_Get_Product_With_Filter() - { - using (var uow = The().Begin()) - { - IEnumerable products = await _productDapperRepository.QueryAsync("SELECT * FROM Products WHERE Title=@Title", new { Title = "Adidas Awesome Sneaker" }); - - products.Count().ShouldBe(1); - products.First().ProductCode.ShouldBe("adidas_code_1"); - - await uow.CompleteAsync(); - } - } - } + public class Domain_ReadModel_With_Dapper_Tests : EntityFrameworkCoreTestBase + { + private readonly IDapperRepository _productDapperRepository; + + public Domain_ReadModel_With_Dapper_Tests() + { + Building(builder => + { + RegisterInMemoryDbContext(builder, opt => new ProductDbContext(opt)); + }).Ok(); + + UsingDbContext(context => + { + context.Products.Add(new Product("Adidas Awesome Sneaker", "adidas_code_1")); + context.Products.Add(new Product("Adidas Awesome Sweatshirt", "adidas_code_2")); + }); + + _productDapperRepository = The>(); + } + + [Fact] + public async Task Should_Get_All_Products() + { + using (var uow = The().Begin()) + { + IEnumerable products = await _productDapperRepository.QueryAsync("SELECT * FROM Products ORDER BY Id"); + + products.Count().ShouldBe(2); + + products.ElementAt(0).ProductCode.ShouldBe("adidas_code_1"); + products.ElementAt(1).ProductCode.ShouldBe("adidas_code_2"); + + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task Should_Get_Product_With_Filter() + { + using (var uow = The().Begin()) + { + IEnumerable products = await _productDapperRepository.QueryAsync("SELECT * FROM Products WHERE Title=@Title", new { Title = "Adidas Awesome Sneaker" }); + + products.Count().ShouldBe(1); + products.First().ProductCode.ShouldBe("adidas_code_1"); + + await uow.CompleteAsync(); + } + } + } } diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/LazyLoading_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/LazyLoading_Tests.cs index a12dd35..f72642b 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/LazyLoading_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/LazyLoading_Tests.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Shouldly; @@ -13,46 +11,46 @@ namespace Stove.EntityFrameworkCore.Tests.Tests { - public class LazyLoading_Tests : EntityFrameworkCoreTestBase - { - private readonly IRepository _blogRepository; - private readonly IRepository _postRepository; - - public LazyLoading_Tests() - { - Building(builder => { }).Ok(); - - _blogRepository = The>(); - _postRepository = The>(); - } - - [Fact] - public async Task Should_Lazy_Load_Collections() - { - using (var uow = The().Begin()) - { - var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); - - blog.ShouldNotBeNull(); - blog.Posts.ShouldNotBeNull(); - blog.Posts.Count.ShouldBeGreaterThan(0); - - await uow.CompleteAsync(); - } - } - - [Fact] - public async Task Should_Lazy_Load_Properties() - { - using (var uow = The().Begin()) - { - var post = await _postRepository.FirstOrDefaultAsync(b => b.Title == "test-post-1-title"); - post.ShouldNotBeNull(); - post.Blog.ShouldNotBeNull(); - post.Blog.Name.ShouldBe("test-blog-1"); - - await uow.CompleteAsync(); - } - } - } + public class LazyLoading_Tests : EntityFrameworkCoreTestBase + { + private readonly IRepository _blogRepository; + private readonly IRepository _postRepository; + + public LazyLoading_Tests() + { + Building(builder => { }).Ok(); + + _blogRepository = The>(); + _postRepository = The>(); + } + + [Fact] + public async Task Should_Lazy_Load_Collections() + { + using (var uow = The().Begin()) + { + var blog = await _blogRepository.FirstOrDefaultAsync(b => b.Name == "test-blog-1"); + + blog.ShouldNotBeNull(); + blog.Posts.ShouldNotBeNull(); + blog.Posts.Count.ShouldBeGreaterThan(0); + + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task Should_Lazy_Load_Properties() + { + using (var uow = The().Begin()) + { + var post = await _postRepository.FirstOrDefaultAsync(b => b.Title == "test-post-1-title"); + post.ShouldNotBeNull(); + post.Blog.ShouldNotBeNull(); + post.Blog.Name.ShouldBe("test-blog-1"); + + await uow.CompleteAsync(); + } + } + } } diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Parallel_Querying_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Parallel_Querying_Tests.cs index 5a12a4f..9c44b73 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/Parallel_Querying_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Parallel_Querying_Tests.cs @@ -27,7 +27,7 @@ public Parallel_Querying_Tests() _parallelQueryExecuteDemo = The(); } - //[Fact] + [Fact(Skip = "Sqlite does not support nested transactions")] public async Task Should_Run_Parallel_With_Different_UnitOfWorks() { await _parallelQueryExecuteDemo.RunAsync(); diff --git a/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs b/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs index 88fe4e5..47fa3ad 100644 --- a/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs +++ b/test/Stove.EntityFrameworkCore.Tests/Tests/Transaction_Tests.cs @@ -27,7 +27,7 @@ public Transaction_Tests() _blogRepository = The>(); } - //[Fact] + [Fact] public async Task Should_Rollback_Transaction_On_Failure() { const string exceptionMessage = "This is a test exception!"; @@ -53,7 +53,7 @@ await _blogRepository.InsertAsync( await UsingDbContextAsync(async context => { var blog = await context.Blogs.FirstOrDefaultAsync(b => b.Name == blogName); - blog.ShouldNotBeNull(); + blog.ShouldBeNull(); }); } } From bf616e141794c5f77c0b2b4556fca775b83afcc6 Mon Sep 17 00:00:00 2001 From: Oguzhan Soykan Date: Thu, 31 May 2018 19:37:47 +0300 Subject: [PATCH 6/6] Version incremented to 2.4.0 --- common.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.props b/common.props index 77c4534..58fefd5 100644 --- a/common.props +++ b/common.props @@ -1,6 +1,6 @@ - 2.3.6 + 2.4.0 $(NoWarn);CS1591 https://raw.githubusercontent.com/osoykan/Stove/master/stove.png https://github.com/osoykan/Stove