Browse Source

Merge pull request #23316 from abpframework/AbpEfCoreNavigationHelper_Tests

Add `AbpEfCoreNavigationHelper_Tests`.
pull/23325/head
Engincan VESKE 7 months ago
committed by GitHub
parent
commit
a06b388851
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs
  2. 96
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEfCoreNavigationHelper_Tests.cs
  3. 5
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs
  4. 16
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs
  5. 31
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/Domain/BlogPost.cs
  6. 17
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs

10
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs

@ -21,10 +21,7 @@ public class AbpEntityEntry
{
return _isModified || EntityEntry.State == EntityState.Modified || NavigationEntries.Any(n => n.IsModified);
}
set
{
_isModified = value;
}
set => _isModified = value;
}
public AbpEntityEntry(string id, EntityEntry entityEntry)
@ -46,14 +43,11 @@ public class AbpEntityEntry
continue;
}
var navigation = EntityEntry.Navigations.FirstOrDefault(n => n.Metadata.Name == navigationEntry.Name);
var currentValue = AbpNavigationEntry.GetOriginalValue(navigation?.CurrentValue);
var currentValue = AbpNavigationEntry.GetOriginalValue(navigationEntry.NavigationEntry.CurrentValue);
if (currentValue == null)
{
continue;
}
switch (navigationEntry.OriginalValue)
{
case null:

96
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEfCoreNavigationHelper_Tests.cs

@ -0,0 +1,96 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.TestApp.Domain;
using Xunit;
namespace Volo.Abp.EntityFrameworkCore;
public class AbpEfCoreNavigationHelper_Tests : EntityFrameworkCoreTestBase
{
private readonly IRepository<Blog, Guid> _blogRepository;
public AbpEfCoreNavigationHelper_Tests()
{
_blogRepository = GetRequiredService<IRepository<Blog, Guid>>();
}
[Fact]
public async Task Performance_Test()
{
//These time taken varies on different machines.
//I used relatively large values, but it can also check for performance problem.
var batchUpdateTime = TimeSpan.FromSeconds(30);
var queryTime = TimeSpan.FromSeconds(10);
if (!Environment.GetEnvironmentVariable("GITHUB_ACTIONS").IsNullOrWhiteSpace())
{
batchUpdateTime = batchUpdateTime * 6;
queryTime = queryTime * 6;
}
var stopWatch = Stopwatch.StartNew();
await WithUnitOfWorkAsync(async () =>
{
for (var i = 0; i < 5 * 1000; i++)
{
await _blogRepository.InsertAsync(
new Blog(Guid.NewGuid())
{
Name = "Blog" + i,
BlogPosts =
[
new BlogPost(Guid.NewGuid())
{
Title = "Post" + i
}
]
});
}
});
stopWatch.Stop();
stopWatch.Elapsed.ShouldBeLessThan(batchUpdateTime);
stopWatch.Restart();
var blogs = await _blogRepository.GetListAsync(includeDetails: true);
blogs.Count.ShouldBe(5 * 1000);
blogs.SelectMany(x => x.BlogPosts).Count().ShouldBe(5 * 1000);
stopWatch.Stop();
stopWatch.Elapsed.ShouldBeLessThan(queryTime);
var blogId = blogs.First().Id;
stopWatch.Restart();
await WithUnitOfWorkAsync(async () =>
{
var blog = await _blogRepository.GetAsync(blogId);
blog.ShouldNotBeNull();
for (var i = 0; i < 5 * 1000; i++)
{
blog.BlogPosts.Add(
new BlogPost(Guid.NewGuid())
{
Title = "NewPost" + i
});
}
await _blogRepository.UpdateAsync(blog);
});
stopWatch.Stop();
stopWatch.Elapsed.ShouldBeLessThan(batchUpdateTime);
var cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.CancelAfter(batchUpdateTime);
stopWatch.Restart();
var blog = await _blogRepository.GetAsync(blogId, cancellationToken: cancellationTokenSource.Token);
blog.BlogPosts.Count.ShouldBe(5 * 1000 + 1);
stopWatch.Stop();
stopWatch.Elapsed.ShouldBeLessThan(queryTime);
}
}

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

@ -53,6 +53,11 @@ public class AbpEntityFrameworkCoreTestModule : AbpModule
{
opt.DefaultWithDetailsFunc = q => q.Include(p => p.OneToOne).ThenInclude(x => x.OneToOne).Include(p => p.OneToMany).ThenInclude(x => x.OneToMany).Include(p => p.ManyToMany);
});
options.Entity<Blog>(opt =>
{
opt.DefaultWithDetailsFunc = q => q.Include(p => p.BlogPosts);
});
});
context.Services.AddAbpDbContext<HostTestAppDbContext>(options =>

16
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs

@ -30,6 +30,9 @@ public class TestMigrationsDbContext : AbpDbContext<TestMigrationsDbContext>
public DbSet<AppEntityWithNavigationsForeign> AppEntityWithNavigationsForeign { get; set; }
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogPost> BlogPosts { get; set; }
public TestMigrationsDbContext(DbContextOptions<TestMigrationsDbContext> options)
: base(options)
{
@ -97,5 +100,18 @@ public class TestMigrationsDbContext : AbpDbContext<TestMigrationsDbContext>
{
b.ConfigureByConvention();
});
modelBuilder.Entity<Blog>(b =>
{
b.ConfigureByConvention();
b.HasMany(bp => bp.BlogPosts)
.WithOne(bp => bp.Blog)
.HasForeignKey(bp => bp.BlogId);
});
modelBuilder.Entity<BlogPost>(b =>
{
b.ConfigureByConvention();
});
}
}

31
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/Domain/BlogPost.cs

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
namespace Volo.Abp.TestApp.Domain;
public class Blog : FullAuditedAggregateRoot<Guid>
{
public Blog(Guid id)
: base(id)
{
}
public string Name { get; set; }
public List<BlogPost> BlogPosts { get; set; }
}
public class BlogPost : Entity<Guid>
{
public BlogPost(Guid id)
: base(id)
{
}
public Guid BlogId { get; set; }
public Blog Blog { get; set; }
public string Title { get; set; }
}

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

@ -1,6 +1,7 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
@ -36,6 +37,9 @@ public class TestAppDbContext : AbpDbContext<TestAppDbContext>, IThirdDbContext,
public DbSet<AppEntityWithNavigationsForeign> AppEntityWithNavigationsForeign { get; set; }
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogPost> BlogPosts { get; set; }
public TestAppDbContext(DbContextOptions<TestAppDbContext> options)
: base(options)
{
@ -123,6 +127,19 @@ public class TestAppDbContext : AbpDbContext<TestAppDbContext>, IThirdDbContext,
b.ConfigureByConvention();
});
modelBuilder.Entity<Blog>(b =>
{
b.ConfigureByConvention();
b.HasMany(bp => bp.BlogPosts)
.WithOne(bp => bp.Blog)
.HasForeignKey(bp => bp.BlogId);
});
modelBuilder.Entity<BlogPost>(b =>
{
b.ConfigureByConvention();
});
modelBuilder.TryConfigureObjectExtensions<TestAppDbContext>();
}
}

Loading…
Cancel
Save