Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Value Object with identity

In an application we have modelled Company as an Entity and Address as a value object:

public class Company : Entity  {
    public Address PrimaryAddress { get; set; }
    public Address SecondaryAddress { get; set; }
}

public class Address : ValueObject {
    public string ZipCode { get; private set; } // etc.

    public Address(string zipCode) {
        ZipCode = zipCode;
    }
}

Here, Address does not have an identity and is immutable. To update the PrimaryAddress of a company I replace it with a new Address object.

However, after further discovery into the domain we found that a company may have a variable number of addresses. Representing them as individual properties was no longer feasible. So we refactored Company:

public class Company : Entity  {
    public Address[] AddressBook { get; set; }
}

We now have a problem of how to update a company's Address. We now care about an address' identity, but only within the context of a Company.

After refactoring we end up with:

public class Company : Entity  {
    public Address[] AddressBook { get; set; }

    public void UpdateAddress(Address newAddress) {
        var oldAddress = AddressBook.FirstOrDefault(a => a.Id == newAddress.Id);
        if (oldAddress != null)
            oldAddress = newAddress;
    }
}

public class Address : ValueObject {
    public Guid Id { get; private set; }
    public string ZipCode { get; private set; } // etc. 

    public Address(Guid id, string zipCode) {
        ZipCode = zipCode;
        Id = id;
    }
}

// usage
var company = repo.Load<Company>(companyId);
var address = new Address(model.Id, "12345"); // uses id of address we are replacing

company.UpdateAddress(address);
repo.Save(company);

To update an address we locate it using its Id and replace it with a new address object with the same Id.

  • Therefore is Address still a value object?
  • Am I right to use the same Id for the updated Address, or by definition (as a value object) should we replace the Id.
  • If the Address only has identity within the context of the Company entity, should we make this explicit in our model, perhaps generating an Id that is only unique inside the entity (perhaps using the entity's id as part of the calculation)?
like image 207
Ben Foster Avatar asked Aug 24 '26 23:08

Ben Foster


1 Answers

Therefore is Address still a value object?

I'd say no, as soon as you give the Address an identity, it ceases being a value object. It means that you stop caring only about its attributes and start giving importance to the Address life cycle in the application, tracking changes in its state, etc.

Am I right to use the same Id for the updated Address, or by definition (as a value object) should we replace the Id.

I wouldn't reuse an Address Id. From a domain standpoint, when a company moves, it's not the address that changes per se. There will still be a valid street number and buildings at that address. The address defined by that identity still has a reality, and you could even imagine reusing it for some other company. Therefore, when a company moves, it's only the association between Company and Address that needs to change to point to an new Address with a new Id.

If the Address only has identity within the context of the Company entity, should we make this explicit in our model, perhaps generating an Id that is only unique inside the entity (perhaps using the entity's id as part of the calculation)?

Just because you feel the need to single out different addresses inside a Company doesn't mean you have to give them an Id and make them Entities rather than value objects. For instance, if you want to rank addresses inside a Company, define a primary Address, etc. you can perfectly do that with value objects. The address value objects will remain the same, you can just have an indexed collection in the Company, a PrimaryAddress field, and so on.

like image 175
guillaume31 Avatar answered Aug 29 '26 09:08

guillaume31



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!