I have two entities with this structure:
public abstract class BaseEntity
{
public BaseEntity()
{
//Validate();
}
public Guid Id { get; set; } = Guid.NewGuid();
public DateTime CreatedAt { get; protected set; } = DateTime.Now;
public bool IsDeleted { get; protected set; }
public DateTime? DeletedAt { get; protected set; }
public DateTime? ModifiedAt { get; set; }
public void SetAsDeleted()
{
DeletedAt = DateTime.Now;
IsDeleted = true;
}
protected abstract void Validate();
}
public class Order : BaseEntity
{
public Person Owner { get; set; }
public long TotalPrice { get; set; }
protected override void Validate()
{
}
}
public class Person : BaseEntity
{
protected Person()
{
Orders = new List<Order>();
}
public Person(string name, string family)
{
Name = name;
Family = family;
Orders = new List<Order>();
}
public void AddOrder(Order order)
{
Orders.Add(order);
}
public void RemoveOrder(Guid id)
{
var item = Orders.FirstOrDefault(x => x.Id == id);
if (item != null)
Orders.Remove(item);
}
protected override void Validate()
{
}
public string Name { get; set; }
public string Family { get; set; }
//private List<Order> _orders;
//public IReadOnlyCollection<Order> Orders => _orders.AsReadOnly();
public List<Order> Orders { get; set; }
}
I configured the relation between these objects like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Person>()
.HasMany(x => x.Orders)
.WithOne(o => o.Owner)
//.OnDelete(DeleteBehavior.SetNull)
.HasForeignKey("OwnerId")
.Metadata.DependentToPrincipal?.SetPropertyAccessMode(PropertyAccessMode.Field);
}
This is my repository:
public class GenericRepository<C,T> : IGenericRepository<T> where T : BaseEntity where C : DbContext
{
protected ILogger<GenericRepository<C, T>> Logger;
protected readonly C DbContext;
public GenericRepository(C dbContext, ILogger<GenericRepository<C,T>> logger)
{
DbContext = dbContext;
Logger = logger;
}
protected IDbConnection DataBaseConnection => DbContext.Database.GetDbConnection();
public virtual async Task SoftDeleteAsync(Guid id)
{
var item = await DbContext.Set<T>().FirstOrDefaultAsync(x => x.Id == id);
item.SetAsDeleted();
await DbContext.SaveChangesAsync();
}
public virtual async Task AddAsync(T entity)
{
await DbContext.Set<T>().AddAsync(entity);
await DbContext.SaveChangesAsync();
}
public virtual async Task UpdateAsync(T entity)
{
DbContext.Attach(entity);
DbContext.Entry(entity).State = EntityState.Modified;
await DbContext.SaveChangesAsync();
}
public virtual async Task<T> GetByIdAsync(Guid id, bool asNoTracking = true)
{
var query = DbContext.Set<T>().AsQueryable();
if (asNoTracking)
query = query.AsNoTracking();
return await query.FirstOrDefaultAsync(x => x.Id == id);
}
public virtual async Task<IEnumerable<T>> QueryAsync(Expression<Func<T, bool>> predict, bool asNoTracking = true)
{
var query = DbContext.Set<T>().Where(predict);
if (asNoTracking)
{
query = query.AsNoTracking();
}
return await query.ToListAsync();
}
}
I am adding an object to the database by running this code:
Person person = new Person("unknown", "person");
person.AddOrder(new Order
{
TotalPrice = 200
});
person.AddOrder(new Order
{
TotalPrice = 300
});
person.AddOrder(new Order
{
TotalPrice = 400
});
await _personRepository.AddAsync(person);
return Ok(person.Id);
It adds one row in the person table and three rows in the orders table.
Now I would like to detach the first order from the person. It means I want to set OwnerId
to null
(not deleting the entire row from the order table).
This is my code:
var person = await _personRepository.GetByIdAsync(id);
person.RemoveOrder(orderid);
await _personRepository.UpdateAsync(person);
return Ok(person.Id);
but the code has no effect on the database and still there are three rows related to the given person.