How To Manage Guard.Against.NotFound for IAggregateRoot

364 views Asked by At

I was wondering if we want to check for adding new item if projectId exist in db, shell we somehow in AddItem method to insert Guard.Agains.NotFound(???) or not? I'm asking because if create some entity:

public class Country : BaseEntity<int>, IAggregateRoot
{
    public string Name { get; private set; }

    private readonly List<District> _districts = new List<District>();
    public IEnumerable<District> Districts => _districts.AsReadOnly();

    public Country(string name)
    {
        Name = Guard.Against.NullOrEmpty(name, nameof(name));
    }

    public void AddDistrict(District newDistrict)
    {
        Guard.Against.Null(newDistrict, nameof(newDistrict));
        Guard.Against.NegativeOrZero(newDistrict.CountryId, nameof(newDistrict.CountryId));

        _districts.Add(newDistrict);
    }
}


public class District : BaseEntity<int>, IAggregateRoot
{
    public string Name { get; set; }
    public int CountryId { get; set; }
    public List<Municipality> Municipalities { get; set; }

}

How we can validate if countryId sent by request exist in DB ? Example if create integration test like :

[Fact]
public async Task AddDistrict()
{
        var districtName = "District";
        var countryRepository = GetCountryRepository();

        var country = new Country("Country");
        await countryRepository.AddAsync(country);
        var district = new District
        {
            CountryId = 2,
            Name = districtName
        };
        country.AddDistrict(district);

        await countryRepository.UpdateAsync(country);

        Assert.Equal(1, district.Id);

}

No matter with intenger value I put as CountryId test will pass till is not 0 or negative integer, but I want to check if that id of country entity exist in DB. Where would be best place to manage this check ? Regards,

1

There are 1 answers

1
Neil W On BEST ANSWER

Simplest way is to request a Country object be provided to the constructor of District:

public class District
{
   public string Name { get; private set; }
   public int CountryId { get; private set; }

   public District(string name, Country country)
   {
       if (country == null)
           throw new Exception("Missing country.");

       Name = name;

       CountryId = country.Id
   }
}

Now you've force the client of the domain to provide a Country. If the client (application layer) cannot retrieve a valid Country from the Country repository based on the provided id then your constructur will throw upon getting a null country.


Alternatively, keep the CountryId as a constructor parameter on District, make the District constructor internal so that it cannot be created outside of the domain and then make the Country object the factory for District:

public class Country
{
    public District CreateDistrict(string name)
    {
        return new District(name, this.Id);
    }
}

This will also force client to get a concrete Country before asking it to create the District.