vkhorikov/CSharpFunctionalExtensions

ValueObject is not equivalent to a Castle.Proxies ValueObject

robertlarkins opened this issue · 5 comments

I'm getting data from an external source that provides a set of type_codes. I have the type_codes as entities in a table. So I'm constructing an object with child objects that each map to the type_code table. In this case an Animal object mapping to Breeds, in which each breed has a breed code.
As this is a fairly long list, I'm going var allBreeds = _context.Breeds.ToList() to get the list of Breeds. Breed has a BreedType ValueObject on it with properties Code and DisplayName. This ValueObject only uses Code for its EqualityComponent. So I form a BreedType ValueObject with the breed_code from the external source and then try to find the reference Breed from allBreeds as it has the entity Id for that breed in the database. The problem seems to be that each breedType is a Castle.Procies.BreedTypeProxy, rather than a straight BreedType, so when I go

var referenceBreed = allBreeds.SingleOrDefault(x => x.BreedType == constructedBreedType);

two ValueObjects with the same code are not equivalent.
How can I make them equivalent, or should I be doing this a different way?

The reason for pulling all the breeds back is so that I'm not doing lots of calls back to the database.

Post the EF Core mappings for Breed and BreedType please.

This is the Configuration for the Breed:

public class BreedConfiguration : IEntityTypeConfiguration<Breed>
{
    public void Configure(EntityTypeBuilder<Breed> builder)
    {
        builder.HasKey(k => k.Id);

        builder.OwnsOne(
            p => p.BreedType, p =>
            {
                p.Property(pp => pp.Code).HasColumnName("breed_type_code");
                p.Property(pp => pp.DisplayName).HasColumnName("display_name");
            });
    }
}

which is called from the Context using this approach

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfiguration(new BreedConfiguration());
}

I don't have a configuration for BreedType (should there be?). The Breed Entity is setup as

public class Breed : Entity
{
	public Breed(BreedType breedType)
	{
		BreedType = breedType;
	}

	protected Breed()
	{
	}

	public virtual BreedType BreedType { get; private set; } = null!;
}

while BreedType ValueObject is

public class BreedType : ValueObject
{
	protected BreedType()
	{
	}

	private BreedType(string code, string displayName)
	{
		Code = code;
		DisplayName = displayName;
	}

	public string Code { get; } = string.Empty;
	public string DisplayName { get; } = string.Empty;

	public static Result<BreedType> Create(string code, string displayName)
	{
		return new BreedType(code, displayName);
	}

	protected override IEnumerable<object> GetEqualityComponents()
	{
		yield return Code;
	}
}

So I'm getting all the breeds in the database using var allBreeds = _context.Breeds.ToList(); and am trying to update an animal's breed reference by assigning it the breed from the database (which has an id).

var allBreeds = _context.Breeds.ToList();
var receivedBreedCode = "ABC";
var receivedBreedType = BreedType.Create(receivedBreedCode, string.Empty).Value;
var storedBreed = allBreeds.SingleOrDefault(x => x.BreedType == receivedBreedType);

But even if allBreeds contains a breed with breedtype code of "ABC" no breed is returned and storedBreed is null. The only difference I can determine is that the BreedType from allBreeds is of type Castle.Proxies.BreedTypeProxy where as receivedBreedType is of BreedType.

Not sure if it makes any difference, but this is working against a postgres database using Npgsql.EntityFrameworkCore.PostgreSQL.

I see the issue now. The original implementation of VO was tailored toward NHibernate, where the ORM doesn't create proxies on top of value objects. Pushed a fix, should be published soon as v2.11.5. Let me know if this fixes the issue.

@vkhorikov Thanks for the quick update to the library, this appears to have fixed my issue.