juliano.net
juliano.net

Reputation: 8177

Delete child entities in a repository

My applications has a repository for each aggregate root, but sometimes I need to remove only one child entity from this aggregate root. How can I do this with the repository pattern?

Ex:

Brand (Aggregate Root)
|_ CarModels (Collection of CarModel)

I need to remove CarModel A from the brand B, however I only have BrandRepository. So how can I achieve this?

I don't know if my code will help you, but here it is:

public class Brand
{
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<CarModel> Models {get;set;}
}

public class CarModel
{
public int id {get;set;}
public string Name {get;set;}
}

public class BrandRepository
{
/// ....

public void Save(Brand entity)
{
this.context.Brands.AddOrUpdate(entity);
this.context.SaveChanges();
}

public void Delete(Brand entity)
{
this.context.Brands.Remove(entity);
this.context.SaveChanges();
}
}

One information that was missing is that I'm using EF code-first.

Upvotes: 1

Views: 1430

Answers (2)

Yugang Zhou
Yugang Zhou

Reputation: 7283

Brand brand = brandRepository.find(brandId);
brand.remove(carModelId);
brandRepository.save(brand);

But DDD seems to be an overkill for displaying data.

Upvotes: 1

Martin4ndersen
Martin4ndersen

Reputation: 2876

I would implement this using Identifying Relationships and a little refactoring of your code.

public class CarModel
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; }
    public string Name { get; set; }
    [Key, ForeignKey("Brand"), Column(Order=1)]
    public int BrandId { get; set; }
    public Brand Brand { get; set; }
}

There are numerous ways to implement the repository pattern and I made as little changes as necessary, although I normally prefer to save changes in a layer higher up.

public class BrandRepository
{
    private readonly Context context;

    public BrandRepository(Context context)
    {
        this.context = context;
    }

    public void Add(Brand brand)
    {
        this.context.Brands.Add(brand);
    }

    public Brand FindByName(string name)
    {
        return this.context.Brands.Single(b => b.Name == name);
    }

    public void RemoveCarModel(Brand brand, string carModelName)
    {
        var carModelToRemove = brand.Models.Single(cm => cm.Name == "A car model");
        brand.Models.Remove(carModelToRemove);
    }

    public void Save()
    {
        context.SaveChanges();
    }

Added a test that adds a brand with two car models and then removes one of the car models.

    [TestMethod]
    public void Test()
    {
        // Arrange.
        using (var context = new Context())
        {
            var models = new List<CarModel> { 
                new CarModel { Name = "A car model" }, 
                new CarModel { Name = "Another car model" }
            };

            var brand = new Brand { Name = "A Brand", Models = models };

            var brandRepository = new BrandRepository(context);
            brandRepository.Add(brand);
            brandRepository.Save();
        }

        // Act.
        using (var context = new Context())
        {
            var brandRepository = new BrandRepository(context);
            var brand = brandRepository.FindByName("A brand");
            brandRepository.RemoveCarModel(brand, "A car model");
            brandRepository.Save();
        }

        // Assert.
        using (var context = new Context())
        {
            var brandRepository = new BrandRepository(context);
            var brand = brandRepository.FindByName("A brand");
            Assert.AreEqual(1, brand.Models.Count);
            Assert.AreEqual("Another car model", brand.Models.Single().Name);
        }
    }

Upvotes: 1

Related Questions