0

If the entity should be always in valid state (therefore the properties are readonly and can be set only by methods which contains validation), How can I build this entity inside Repository without executing validations, because I suppose that database state is always valid ? Or should i always excecute validations even if the data source is database ?

For example i have this AggregateEntity Customer

public class Customer
    {
        public int Id { get; private set; }
        public string CompanyName { get; private set; }
        public string ContactEmailHeadOffice { get; private set; }

        private List<Office> _offices = new List<Office>();
        public IEnumerable<Office> Offices => _offices.AsReadOnly();

        public void AddOffice(Office office, IRemoteDatabaseRepository repository)
        {
            office.Validate(); // May throw BusinessRuleException.

            if (!repository.DoRegistrationTokenExistForThisCustomer(Id, office.RegistrationToken))
            {
                throw new BusinessRuleException($"Registration token {office.RegistrationToken} does not exist for customer id {Id}.");
            };

        }
    }

But what is recommended way of populating the properties includes _offices collection ?

What should CustomerRepository.Retrieve(int customerId) contains ?

I want to avoid unnecessary validation and I want to be able to set the entity properties for the purpose of unit testing and also be able to get populated entity from the database.

1
1

You could remove validation from the constructor, make the constructor internal, and call it from the repository to allow unvalidated object creation. If the repository is in a separate assembly, use https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute?view=netframework-4.8

Next add a public static factory method to perform validation before returning a new object.

The internal constructor is also convenient for unit testing.

Another bonus is that a the static factory method can return some form of ValidationResult object instead of throwing exceptions.

2
  • this is great, thank you i will try it :) – Muflix May 4 '19 at 17:32
  • it is really working ! :) – Muflix May 4 '19 at 18:00
0

Another solution is to use backing fields which allows entity framework to set private field directly.

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Customer configuration.
            modelBuilder.Entity<Customer>().ToTable("Customer", schema: "dbo").HasKey(x => x.Id);
            // Allow EF to access private collection field.
            modelBuilder.Entity<Customer>()
                .HasMany(c => c.Offices)
                .WithOne()
                .Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field);

            modelBuilder.Entity<Office>().ToTable("Office", schema: "dbo").HasKey(x => x.Id);
        }

so I can call (otherwise without backing field, read only exception is thrown)

Customer customer = _context.Customers.Where(x => x.Id == customerId).Include("Offices").FirstOrDefault();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.