Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting object from collection Domain Driven Design

In our project we are following Domain Driven Design with entity framework. Recently i came upon one issue where i want to delete a object from collection . Lets say Customer have collection of purchase. I want to remove the particular purchase of one customer.

 public class Customer
{
    public int ID { get; set; }

    public string Name { get; set; }

    public string Address { get; set; }

    public virtual ICollection<Purchase> Purchases { get; set; }
}

public class Purchase
{
    public int ID { get; set; }

    public int CustomerId { get; set; }

    public DateTime PurchaseDate { get; set; }
}

I tried to remove the purchase by

customer.Purchases.Remove(purchase);

but the above code removed only the relation not deleting the purchase from db . I want to remove them from db.

So to make that work i have given that responsibility to Repository and used context object inside repository to remove the purchase.

repository.DeletePurchase(purchase);

Is the above is right approach in Domain Driven Design or any possibilities to move the delete behavior within entity?

Pleas help me the follow the best practice to implement DDD.

like image 897
Max_dev Avatar asked Sep 05 '25 02:09

Max_dev


2 Answers

What is problematic to answer here is that I have no idea what behavior you're executing. "Removing the purchase of a customer" ... the more important question is why and when that's allowed/appropriate. Even then, purchases are somewhat of a transaction, what's the point of removing them (pretending they didn't happen, loosing history along the way). Your design is also problematic. What if I purchase something every day of the year? How many purchases will I need to load up just to remove that single purchase when we fast forward a year from now? How about modeling a purchase as a separate aggregate and just copy the id of the customer it is for? We can always find out all purchases of a customer using nothing but predicate on that customer id. Would that make sense in your context?

Time and time people forget to formulate the actual behavior they're trying to model, and adding proper context for the future reader is but a distant dream. Getting intimate with your domain and model are not optional.

like image 192
Yves Reynhout Avatar answered Sep 09 '25 01:09

Yves Reynhout


If you are following Domain Driven Design, an implementation of your collections should follow best practices (e.g. collection should be exposed as read-only, without setter, with AddPurchase/ DeletePurchase methods).

I assume that Purchase is not deleted because context.SaveChanges() is not invoked.

Unfortunately it also might be a known issue Entity cannot be deleted from child collection but can be from context.

EDIT : There are two options and all of them are not good enough.

  1. context.Set<Purchase>().Remove(purchase); can be invoked.
  2. Composite Primary key (Id + CustomerId) can be used for Purchase entity.

        modelBuilder.Entity<Purchase>()
            .HasRequired(it => it.Customer)
            .WithMany(it => it.Purchases)
            .HasForeignKey(it => it.CustomerId);
    
        modelBuilder.Entity<Purchase>().HasKey(it => new
            {
                Id = it.Id,
                CustomerId = it.CustomerId
            });
    

    By default HasKey() prevents identity. That's why it should be specified as attribute.

    public class Purchase
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
    
        public Customer Customer { get; set; }
    
        public int CustomerId { get; set; }
    
        public DateTime PurchaseDate { get; set; }
    }
    

There are some related discussions:

  1. Error when deleting one-to-many children
  2. A relationship is in the Deleted state
  3. Is it possible to remove child from collection and resolve issues on SaveChanges?
like image 20
Ilya Palkin Avatar answered Sep 09 '25 03:09

Ilya Palkin