Hi @EngincanV,
I have created a 3rd example app, of the User & UserProfile example inside an ABP framework solution: https://cdn.fuzed.app/share/abp/AbpEFCorePlayground.zip
This time the SQL query loop occurs again, within ABP framework, using the same configuration as previous example. So I think this is some framework issue that needs to be fixed.
User entity:
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace AbpEFCorePlayground.Users;
public class User : FullAuditedAggregateRoot<Guid>
{
public User(
Guid id,
string name)
{
Id = id;
Name = name;
}
private User()
{
}
public string Name { get; set; }
public UserProfile? Profile { get; set; }
}
UserProfile entity:
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace AbpEFCorePlayground.Users;
public class UserProfile : FullAuditedEntity<Guid>
{
public Guid Id { get; set; }
public string Bio { get; set; }
public Guid UserId { get; set; }
public User User { get; set; }
}
UsersDataSeedContributor:
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpEFCorePlayground.Users;
public class UsersDataSeedContributor : IDataSeedContributor, ITransientDependency
{
private readonly IUserRepository _userRepository;
public UsersDataSeedContributor(IUserRepository userRepository)
{
_userRepository = userRepository;
}
[UnitOfWork]
public virtual async Task SeedAsync(DataSeedContext context)
{
User user = new User(
id: Guid.Parse("c64b873e-c067-43e0-ae00-07992a880837"),
name: "Steff Beckers")
{
Profile = new UserProfile()
{
Bio = "Software Developer"
}
};
await _userRepository.DeleteAsync(x => x.Id == user.Id);
await _userRepository.InsertAsync(user);
}
}
EF entity configuration:
builder.Entity<User>(b =>
{
b.ToTable(AbpEFCorePlaygroundConsts.DbTablePrefix + "Users", AbpEFCorePlaygroundConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.HasOne(x => x.Profile)
.WithOne(x => x.User)
.HasForeignKey<UserProfile>(x => x.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
});
builder.Entity<UserProfile>(b =>
{
b.ToTable(AbpEFCorePlaygroundConsts.DbTablePrefix + "UserProfiles", AbpEFCorePlaygroundConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
});
Configure<AbpEntityOptions>(options =>
{
options.Entity<User>(e =>
{
e.DefaultWithDetailsFunc = query => query.Include(x => x.Profile);
});
});
App service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbpEFCorePlayground.Users;
public class UsersAppService : AbpEFCorePlaygroundAppService, IUsersAppService
{
private readonly IUserRepository _userRepository;
public UsersAppService(IUserRepository userRepository)
{
this._userRepository = userRepository;
}
public async Task DeleteUserProfileAsync()
{
var user = await _userRepository.GetAsync(x => x.Id == Guid.Parse("c64b873e-c067-43e0-ae00-07992a880837"));
user.Profile = null;
await _userRepository.UpdateAsync(user);
}
}
Best regards, Steff Beckers
Hi @EngincanV,
I've tested IsRequired(false) and it solves the query issue, but the Author itself isn't deleted. An author can't exist on its own in this case and now we have a "ghost" Author record, since BookId is now allowed to be NULL. So I don't think we should use IsRequired(false). IsRequired configures whether this is a required relationship (i.e. whether the foreign key property(s) can be assigned null). It doesn't ensure that a Book requires an Author. It only ensures that the FK is required/can't be NULL => an Author must have a BookId.
Also see the EF core docs: https://learn.microsoft.com/en-us/ef/core/modeling/relationships/one-to-one#required-one-to-one
I've created a new and better (relation wise) example using the ASP.NET Core Web API template, where the removal works as expected: https://cdn.fuzed.app/share/abp/EFCorePlayground.zip
Entities:
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public UserProfile? Profile { get; set; }
}
public class UserProfile
{
public Guid Id { get; set; }
public string Bio { get; set; }
public Guid UserId { get; set; }
public User User { get; set; }
}
DbContext:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<User> Users { get; set; }
public DbSet<UserProfile> UserProfiles { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOne(x => x.Profile)
.WithOne(x => x.User)
.HasForeignKey<UserProfile>(x => x.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
}
}
Controller:
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private readonly AppDbContext _context;
public UsersController(AppDbContext context)
{
_context = context;
}
...
// DELETE: api/users/{id}/profile
[HttpDelete("{id}/profile")]
public async Task<IActionResult> DeleteUserProfile(Guid id)
{
User? user = await _context.Users.Include(x => x.Profile).FirstOrDefaultAsync(x => x.Id == id);
if (user == null)
{
return NotFound();
}
user.Profile = null;
await _context.SaveChangesAsync();
return NoContent();
}
...
}
Thanks in advance!
Best regards, Steff Beckers
It seems I still had to clear my local NuGet cache to resolve the warnings.
I got the same issue
While investigating the bundling I saw a lot of logs related to the bundling. Can you check if this is correct, since I see a lot of the same files getting bundled and minified? Or are these from multiple requests? Also, notice the timestamps.
https://cdn.fuzed.app/share/abp/main-http-api-6f5c75958b.log
Thanks!
Can you share this project or make a simple project?
I can't share our source code. With the test project I tried to create, I coudn't reproduce the same warnings..
Yes, we still can reproduce the issue in our application without SetMinThreads
. When the Redis cache is cleared or expired, if we then request a web page, which triggers a lot of API requests (due loading image thumbnails), then the Redis timeout warnings are logged.
Hi @maliming, I've tried to create a test app, but I couldn't reproduce the same warnings we got from the Redis timeouts. We monitored the thread pool usage:
dotnet-counters monitor --counters System.Runtime -n Fuzed.HttpApi.Host
In the end we ended up updating the min worker threads in our app:
ThreadPool.GetMinThreads(out int minWorkerThreads, out int minCompletionPortThreads);
ThreadPool.SetMinThreads(100, minCompletionPortThreads);
Thanks!
hi @s.beckers
Can you share your test project?
liming.ma@volosoft.com
Thanks.
Hi @maliming, I'll try to create a test project and send it to you.