Reputation: 861
I have an issue with Owned Types on my entites, because I added an override for SaveChanges to make soft-deletes possible. Basically I override the state of the Entity to modified instead of delete in the SaveChanges and add some meta information to the entity. This works well unless I add a OwnedType onto the entity.
When I do this, EF tries to set all values from the OwnedType to NULL, which is not possible in my example because the Strings are not nullable.
I am not exactly sure how I can fix this behaviour, because I need to set the DeleteBehaviour to NoAction, but I couldn't find a way to do this at the moment. Can anyone explain to me how I can solve this issue?
MainEntity.cs
public class MainEntity: SoftDeleteEntityBase
{
public int Id { get; set; }
public LocalizedStringSet MultilangTitle { get; set; } = new LocalizedStringSet();
}
LocalizedStringSet.cs
public class LocalizedStringSet
{
[MaxLength(4000)]
public string En { get; set; } = string.Empty;
[MaxLength(4000)]
public string Fr { get; set; } = string.Empty;
}
MainEntityConfiguration.cs
public class MainEntityConfiguration : IEntityTypeConfiguration<MainEntity>
{
public void Configure(EntityTypeBuilder<MainEntity> builder)
{
if (builder is null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.HasKey(x => x.Id);
builder.Property(x => x.Id).ValueGeneratedOnAdd();
builder.OwnsOne(o => o.MultilangTitle);
}
}
ApplicationDbContext.cs
public override int SaveChanges()
{
if (entry.Entity is ISoftDeleteEntityBase managedCreationSoftDelete)
{
switch (entry.State)
{
case EntityState.Deleted:
{
entry.State = EntityState.Modified;
managedCreationSoftDelete.DeletedBy = creator;
managedCreationSoftDelete.Deleted = DateTime.Now;
break;
}
}
}
return base.SaveChanges();
}
Upvotes: 2
Views: 897
Reputation: 21
I had the same issue with the same workflow, marking entities as ISoftDeleteEntityBase
and then handling this. For entities not marked with this, delete works as normal (owned entities).
It might not be the best solution, but I fixed this with another interface I tagged owned entities with:
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State != EntityState.Deleted) break;
if (entry.Entity is IOwnedEntity)
{
entry.State = EntityState.Unchanged;
}
if (entry.Entity is ISoftDeletedDatabaseEntity && entry.State == EntityState.Deleted)
{
entry.State = EntityState.Modified;
entry.CurrentValues[nameof(ISoftDeletedDatabaseEntity.DeletedOn)] = DateTime.UtcNow;
entry.CurrentValues[nameof(ISoftDeletedDatabaseEntity.IsDeleted)] = true;
}
}
Upvotes: 0
Reputation: 861
I found a way to solve it, but I am not sure if there is a better way to do this.
public override int SaveChanges()
{
if (entry.Entity is ISoftDeleteEntityBase managedCreationSoftDelete)
{
switch (entry.State)
{
case EntityState.Deleted:
{
entry.State = EntityState.Modified;
managedCreationSoftDelete.DeletedBy = creator;
managedCreationSoftDelete.Deleted = DateTime.Now;
foreach (var reference in entry.References)
{
if (reference.TargetEntry?.Entity.GetType() == typeof(LocalizedStringSet))
{
if (reference.TargetEntry != null)
{
reference.TargetEntry.State = EntityState.Unchanged;
}
}
}
break;
}
}
}
return base.SaveChanges();
}
Upvotes: 2