To help developers find answers more quickly, we have collected all frequently asked questions into a single, easy-to-use FAQ index thread. Instead of searching through pinned items on the homepage, you can now browse organized categories based on your development needs.
See all FAQ labelled questions -> https://abp.io/support/questions?Sort=LastActivityDate-desc&TagNames=faq
BTW, the name of this thread should probably change now in 2025.
Thanks for reminding. I'm closing this thread and creating a fresh one, which you can follow at https://abp.io/support/questions/8803/ABP-Suite-feature-request--2025
We have created internal issues for ABP Suite related feature-requests and will consider them and try to implement them in our each version. Thank you all for your interest and if you still have new feature-request, please list them in the new thread.
Best Regards.
What feature would you like to see in ABP Suite in the new version?
Continuation thread of https://abp.io/support/questions/6529/ABP-Suite-feature-request--2024
Hi @EngincanV,
Hi, since in your entity configuration the UserProfile has a not nullable UserId field you can't set the user.Profile as null without deleting the userProfile.
Added a new DeleteProfile method in user repository:
public class EfCoreUserRepository : EfCoreRepository<AbpEFCorePlaygroundDbContext, User, Guid>, IUserRepository { public EfCoreUserRepository( IDbContextProvider<AbpEFCorePlaygroundDbContext> dbContextProvider) : base(dbContextProvider) { } public async Task DeleteProfileAsync(User user) { if (user.Profile == null) { return; } AbpEFCorePlaygroundDbContext dbContext = await GetDbContextAsync(); dbContext.Remove(user.Profile); user.Profile = null; } }
Update in app service:
public async Task DeleteUserProfileAsync() { var user = await _userRepository.GetAsync(x => x.Id == Guid.Parse("c64b873e-c067-43e0-ae00-07992a880837")); if (user.Profile == null) { return; } await _userRepository.DeleteProfileAsync(user); await _userRepository.UpdateAsync(user); }
The user updated event is correct:
But when I continue after the breakpoint, the request still keeps executing, because of the infinite loop in the AbpDbContext:
![]()
And the user profile is not deleted in the database.
Best regards, Steff Beckers
Hi, the problem in your code is that both the User
and the UserProfile
entities use the soft-delete, which means when you delete a user profile, it's not deleted in normally, only its IsDeleted field set to true and it becomes invisible in your SQL queries, if you apply dataFilters and ABP applies it by default (https://abp.io/docs/9.0/framework/infrastructure/data-filtering#isoftdelete). Therefore, you can't set the user.Profile
as null, because the profile is soft-deleted, not hard-deleted. This is the difference between your EfCorePlayground and AbpEfCorePlayground applications.
If you want the UserProfile as hard deleted, then you can use the IDataFilter service. Example:
private readonly IDataFilter _dataFilter;
using (_dataFilter.Disable<ISoftDelete>())
{
//hard deletes from your db
await _userProfileRepository.DeleteAsync(user.Profile!.Id, autoSave: true);
}
Hi, since in your entity configuration the UserProfile
has a not nullable UserId
field you can't set the user.Profile as null without deleting the userProfile.
Hi @EngincanV,
and make the UserId as nullable
A UserProfile record can't exist without a reference to a User, so the UserId on UserProfile should not be nullable.
Best regards, Steff Beckers
Hi, then you can directly delete the userProfile instead of setting user.Profile as null. This is the only solution. If you want to set the user's profile as null it should be nullable, or if you directly delete the profile, it will be empty further on.
Regards.
Hello,
I looked over the documentation that you sent and tried using the Audited attribute, but this did not give me what I was looking for.
I am trying to manually add a history log entry to our User entity for changes that are not occurring in the User table. The changes occur on our UserAssignedMerchant join table.
Here is some additional context on our User implementation:
- We implemented our own User class and dtos, but are using IdentityUserManager calls that we adapted from source code to set the properties to still use the built in AbpUsers table and features in our create and update methods.
- Also during those methods, we set the entries in the join table with repository calls for the join table.
- We give the UserAssignedMerchant entries to the end users in a field that is a Guid[] called AssignedMerchantIds, but this only on the dto not the class so it's manually set at the time of retrieval.
Is there a repository call (such as through IAuditLogRepository) that we can make to insert a history log on User that will allow us to manually set what changed in AssignedMerchantIds? Or is there a better way to accomplish this?
Thanks.
Hi, you can configure the AbpAuditingOptions
and define an EntityHistorySelector as below:
opt.EntityHistorySelectors.Add(
new NamedTypeSelector(
"UserAssignedMerchant",
type => typeof(UserAssignedMerchant).IsAssignableFrom(type)
));
Hi @EngincanV,
Hi, based on your EfCorePlayground project, you can call _context.UserProfiles.Remove(user.Profile!) method before setting user.Profile to null:
The EfCorePlayground project doesn't have the issue, the AbpEfCorePlayground project has.
Best regards, Steff Beckers
Hi, here is what you need to do to:
1 -) In your UserProfile entity, remove the Id
property (because it's already defined by the base class FullAuditedEntity<Guid>
), and make the UserId
as nullable:
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; }
}
2-) Open your dbcontext class and update the configuration:
b.HasOne(x => x.Profile)
.WithOne(x => x.User)
.HasForeignKey<UserProfile>(x => x.UserId)
.OnDelete(DeleteBehavior.ClientSetNull);
You should use the
ClientSetNull
as the delete-behaviour, which is default and allows you to set the Profile as null.
3-) Update your DeleteUserProfileAsync
method:
public async Task DeleteUserProfileAsync()
{
var user = await _userRepository.GetAsync(x => x.Id == Guid.Parse("c64b873e-c067-43e0-ae00-07992a880837"));
await _userProfileRepository.DeleteAsync(user.Profile!.Id);
user.Profile = null;
await _userRepository.UpdateAsync(user);
}
Then, it will work as you expected.
Regards.
Hi @EngincanV,
I have the following User aggregate root:
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; } }
I also have an User record in my database (via IDataSeedContributor):
User user = new User( id: Guid.Parse("c64b873e-c067-43e0-ae00-07992a880837"), name: "Steff Beckers") { Profile = new UserProfile() { Bio = "Software Developer" } }; await _userRepository.InsertAsync(user);
Now I want to delete the user's profile. What I'm thinking is:
var user = await _userRepository.GetAsync(userId); user.Profile = null; await _userRepository.UpdateAsync(user);
But this results in the error. How else should I delete the user's profile?
Best regards, Steff Beckers
Hi, based on your EfCorePlayground project, you can call _context.UserProfiles.Remove(user.Profile!)
method before setting user.Profile to null:
_context.UserProfiles.Remove(user.Profile!);
user.Profile = null;
If you want to do this with repository pattern, then you should inject the profile repository and use its DeleteAsync method:
//inject the interface
private readonly IRepository<UserProfile, Guid> _userProfileRepository;
var user = await _userRepository.GetAsync(userId);
await _userProfileRepository.DeleteAsync(user.Profile!.Id);
user.Profile = null;
await _userRepository.UpdateAsync(user);
Hi @EngincanV,
Any progress on this issue?
Best regards, Steff Beckers
Hi sorry for my late response,
In SQL Server, a foreign key constraint only enforces referential integrity—it does not define what should happen when the navigation property (Profile
) is set to null. SQL Server only responds to actual DELETE operations.
Example: If you set user.Profile = null
, EF Core only removes the reference, but SQL Server still holds the Profile
record because there’s no explicit DELETE query for it.
SQL Server requires an explicit cascade delete at the database level to automatically remove dependent entities.
So, this is not related to ABP or EF Core, instead, it's the design of the SQL Server.
DeleteBehavior.Cascade
Only Works When the Principal Entity is Deleted. So, in your case, the relevant profile is deleted whenever the relevant user is being deleted.
Also, there is a good description here that you might want to check: https://stackoverflow.com/a/12886309/10477283