3
votes

I add a navigation property from Customer to Purchase (as a collection) in my Entity Framework project. The relationship already existed before, so no database migration is performed.

When I retrieve a non-empty set of Product - which also has a navigation property to Purchase (as a collection) - from the context, I get the following exception:

The 'BrandID' property on 'BrandedProduct' could not be set to a 'null' value. You must set this property to a non-null value of type 'System.Int32'.

Simplified code (all entities also have an ID property and a protected/public empty constructor):

public class Customer {
    // Adding this line causes the exception. Without it, everything works fine.
    public virtual ICollection<Purchase> Purchases { get; private set; }
}

public abstract class Product {
    public virtual ICollection<Purchase> Purchases { get; private set; }
}

public class BrandedProduct : Product {
    // This is the property that EF tries to set to null
    public int BrandID { get; private set; }

    public virtual Brand Brand { get; private set; }
}

public class Brand {}

// This works as a many-to-many relationship between Product and Customer
public class Purchase {
    public int CustomerID { get; private set; }
    public int ProductID { get; private set; }

    public virtual Customer Customer { get; private set; }
    public virtual Product Product { get; private set; }

    // Other properties...
}

The Purchase class has a composite primary key, so the following configuration is set up in the DataContext class.

public class DataContext : DbContext {
    protected override void OnModelCreating(DbModelBuilder builder) {
        builder.Entity<Purchase>().HasKey(x => new { x.CustomerID, x.ProductID });
    }
}

Any idea why this could happen?

1
Just curious, are those your POCOs? Why do you have a private setter on your ID properties?Frank Fajardo
I am not totally familiar with the concept POCO, but these classes form a pure domain model without any references to Entity Framework. I use code-first migrations and all entities also have an ID. Database constraints are defined using EntityTypeConfigurations, like the last code block in my question, in a separate project. Private setters is just a preference I have, can that cause any problems? :)ajgarn
If you are retrieving data through these classes, how would the ID's be populated if the setters are private?Frank Fajardo
Well, EF can actually populate a class with private setters. Lazy loading works as well - just make sure that the constructor is at least protected. For my domain, I use constructors and/or methods to mutate the objects.ajgarn
You are right; I didn't know that. Thanks for the info. :)Frank Fajardo

1 Answers

0
votes

In this example, it looks like the problem is due to BrandedProduct not having a primary key which is required by Entity Framework. It is attempting to figure out and set BrandID as the primary key, which has a private setter.

To solve this, just add the [Key] attribute or another HasKey to your configuration for a property with a public setter.