EF exception, how to model addresses in c# and entity framework code first

Michael Tranchida

EF is throwing the following exception:

System.InvalidOperationException: Referential integrity constraint violation. A Dependent Role has multiple principals with different values.

I have two entities, StateProvince and Country:

public class StateProvince
{
    public long Id { get; set; }

    [StringLength(100)]
    public string Name { get; set; }

    public long CountryId { get; set; }
    public Country Country { get; set; }
}

public class Country
{
    public long Id { get; set; }

    [StringLength(2)]
    public string Code { get; set; }

    public IEnumerable<StateProvince> StatesProvinces { get; set; }
}

and two entities that use them:

public class Customer
{
    public long Id { get; set; }

    public long BillingStateProvinceId { get; set; }
    [ForeignKey("Id")]
    public StateProvince BillingStateProvince { get; set; }

    public long BillingCountryId { get; set; }
    [ForeignKey("Id")]
    public Country BillingCountry { get; set; }

    public long ShippingStateProvinceId { get; set; }
    [ForeignKey("Id")]
    public StateProvince ShippingStateProvince { get; set; }

    public long ShippingCountryId { get; set; }
    [ForeignKey("Id")]
    public Country ShippingCountry { get; set; }
}

public class Vendor
{
    public long Id { get; set; }

    public long StateProvinceId { get; set; }
    public StateProvince StateProvince { get; set; }

    public long CountryId { get; set; }
    public Country Country { get; set; }
}

And in my OnModelCreating:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.ShippingStateProvince)
            .WithOptional().WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.ShippingCountry)
            .WithOptional().WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.BillingStateProvince)
            .WithOptional().WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.BillingCountry)
            .WithOptional().WillCascadeOnDelete(false);

        modelBuilder.Entity<Vendor>()
            .HasRequired(m => m.StateProvince)
            .WithOptional().WillCascadeOnDelete(false);

        modelBuilder.Entity<Vendor>()
            .HasRequired(m => m.Country)
            .WithOptional().WillCascadeOnDelete(false);

        base.OnModelCreating(modelBuilder);
    }

Finally, the code that throws the exception:

[TestMethod]
    public void TestMethod1()
    {
        Db db = new Db();

        #region Set/reset items

        Country us = db.Countries.FirstOrDefault();
        if (us == null)
        {
            us = new Country { Code = "US" };
            db.Countries.Add(us);
            db.SaveChanges();
        }
        long usId = us.Id;

        List<StateProvince> states = db.StateProvinces.ToList();
        StateProvince mass = states.Where(m => m.Name == "MA").FirstOrDefault();
        StateProvince ct = states.Where(m => m.Name == "CT").FirstOrDefault();
        if (mass == null)
        {
            mass = new StateProvince { Name = "MA", CountryId = usId };
            ct = new StateProvince { Name = "CT", CountryId = usId };
            db.StateProvinces.Add(mass);
            db.StateProvinces.Add(ct);
            db.SaveChanges();
        }
        long massId = mass.Id;
        long ctId = ct.Id;

        List<Customer> customersToRemove = db.Customers.ToList();
        db.Customers.RemoveRange(customersToRemove);
        db.SaveChanges(); 

        #endregion

        Customer customerToAdd = new Customer { 
            BillingStateProvinceId = massId, 
            ShippingStateProvinceId = ctId, 

            ShippingCountryId = usId, 
            BillingCountryId = usId,

            BillingStateProvince = mass,
            ShippingStateProvince = ct,

            BillingCountry = us,
            ShippingCountry = us
        };

        db.Customers.Add(customerToAdd);

        try
        {
            //exception thrown here
            db.SaveChanges();
        }
        catch (Exception e)
        {
            throw;
        }

        db.Dispose();

        Db dbCheck = new Db();

        Customer customer = dbCheck.Customers.Include(m => m.BillingStateProvince).Include(m => m.ShippingStateProvince).FirstOrDefault();

        dbCheck.Dispose();
    }

I suspect the issue is either I'm not using the [ForeignKey] attribute correctly or I'm doing something wrong in OnModelCreating. I can make it work if I only have one StateProvince and one Country entity in the Customer entity, however, once I have two, can't figure it out. Any help?

On a broader note does anyone have any links to blogs/posts/articles/tutorials on how to model addresses with c# EF code first? I came across this one, which uses the [ComplexType] attribute, the problem there is that I can't encapsulate the StateRegion and Country classes within it. My current thinking is to just bake in the various address fields into each class, i.e. MailingStreetAddress, BillingStreetAddress, etc. I would like to see how others have handled addresses to gain a better understanding on how to do my own.

Edit

Per @Sam I am, I tried to change attribute to:

[ForeignKey("BillingStateProvinceId")]

for each property. Upon dropping/recreating the db, EF threw this error:

Customer_BillingCountry_Source: : Multiplicity is not valid in Role 'Customer_BillingCountry_Source' in relationship 'Customer_BillingCountry'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be ''. Customer_BillingStateProvince_Source: : Multiplicity is not valid in Role 'Customer_BillingStateProvince_Source' in relationship 'Customer_BillingStateProvince'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be ''. Customer_ShippingCountry_Source: : Multiplicity is not valid in Role 'Customer_ShippingCountry_Source' in relationship 'Customer_ShippingCountry'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be ''. Customer_ShippingStateProvince_Source: : Multiplicity is not valid in Role 'Customer_ShippingStateProvince_Source' in relationship 'Customer_ShippingStateProvince'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be ''.

Edit 2

Per @Steve Green, changed my StateRegion, Country entities, and OnModelCreating, which now throws this error when I drop recreate the db:

Schema specified is not valid. Errors: The relationship 'StackOverflow.Customer_ShippingCountry' was not loaded because the type 'StackOverflow.Country' is not available.

My edited code:

public class StateProvince
{
    public long Id { get; set; }

    [StringLength(100)]
    public string Name { get; set; }

    //new properties
    public ICollection<Customer> Customers { get; set; }
    public ICollection<Vendor> Vendors { get; set; }

    public long CountryId { get; set; }
    public Country Country { get; set; }
}

public class Country
{
    public long Id { get; set; }

    [StringLength(2)]
    public string Code { get; set; }

    //new properties
    public ICollection<Customer> Customers { get; set; }
    public ICollection<Vendor> Vendors { get; set; }

    public IEnumerable<StateProvince> StatesProvinces { get; set; }
}

And my OnModelCreating to mirror his:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.ShippingStateProvince)
            .WithMany(m => m.Customers)
            .HasForeignKey(m => m.ShippingStateProvinceId);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.ShippingCountry)
            .WithMany(m => m.Customers)
            .HasForeignKey(m => m.ShippingCountryId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.BillingStateProvince)
            .WithMany(m => m.Customers)
            .HasForeignKey(m => m.BillingStateProvinceId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.BillingCountry)
            .WithMany(m => m.Customers)
            .HasForeignKey(m => m.BillingCountryId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Vendor>()
            .HasRequired(m => m.StateProvince)
            .WithMany(m => m.Vendors)
            .HasForeignKey(m => m.StateProvinceId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Vendor>()
            .HasRequired(m => m.Country)
            .WithMany(m => m.Vendors)
            .HasForeignKey(m => m.CountryId)
            .WillCascadeOnDelete(false);

        base.OnModelCreating(modelBuilder);
    }
Steve Greene

Since you already have a fluent config, you could go with something like this and forgo the annotations:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.StateProvince)
            .WithMany() 
            .HasForeignKey(c => c.ShippingStateProvinceId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.Country)
            .WithMany() 
            .HasForeignKey(c => c.ShippingCountryId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.StateProvince)
            .WithMany() 
            .HasForeignKey(c => c.BillingStateProvinceId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Customer>()
            .HasRequired(m => m.Country)
            .WithMany() 
            .HasForeignKey(c => c.BillingCountryId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Vendor>()
            .HasRequired(m => m.StateProvince)
            .WithMany() 
            .HasForeignKey(c => c.StateProvinceId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Vendor>()
            .HasRequired(m => m.StateProvince)
            .WithMany() 
            .HasForeignKey(c => c.CountryId)
            .WillCascadeOnDelete(false);


        base.OnModelCreating(modelBuilder);
    }

https://msdn.microsoft.com/en-us/data/jj591620.aspx#Model

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Entity Framework Code First 6 - Invalid Operation Exception when i put entity state ? Posible EF Bug?

From Dev

Code first Entity Framework model in PHP

From Dev

Entity Framework Code First Tree Model

From Dev

How to change from Model-first to Code-First in Entity Framework

From Dev

Switching from entity framework model first to code first

From Dev

C# Model User, Friend Requests and Friends with Entity Framework Code First

From Dev

Entity Framework code first: How to ignore classes

From Dev

Entity Framework code first causes exception on database access

From Dev

How to use Entity Framework code-first with a newer database model version

From Dev

How to Keep Entity Framework Code First from using Derived Classes that Aren't Part of the Model

From Dev

Entity framework model first connection string how to change while moving code to server

From Dev

Error in Seed Method of Entity Framework, Tables not created in Code First Model

From Dev

Entity Framework 5 code first cannot get model to work

From Dev

Entity Framework 5 code first cannot get model to work

From Dev

Entity Framework 6 Code First: specific model design implementation

From Dev

BaseEntity in Entity Framework Model First

From Dev

entity framework code first migration working in EF5 but not in EF6

From Dev

Best way to use Entity Framework (Database First , Model First , Code First)

From Dev

How do I map a C# int to a SqlServer tinyint using Entity Framework Code First?

From Dev

WCF with Entity Framework Code First

From Dev

Entity Framework Inheritance Code First

From Dev

Relationships in Entity Framework Code First

From Dev

Entity Framework Code First connection

From Dev

Entity Framework Code First GenericTypeArguments

From Dev

WCF with Entity Framework Code First

From Dev

Entity Framework - Code First - Relationship

From Dev

Entity Framework Code First - Relationships

From Dev

Sample for Entity Framework 6 + Code First + Oracle 12c

From Dev

C# - Entity Framework - Large seed data code-first

Related Related

  1. 1

    Entity Framework Code First 6 - Invalid Operation Exception when i put entity state ? Posible EF Bug?

  2. 2

    Code first Entity Framework model in PHP

  3. 3

    Entity Framework Code First Tree Model

  4. 4

    How to change from Model-first to Code-First in Entity Framework

  5. 5

    Switching from entity framework model first to code first

  6. 6

    C# Model User, Friend Requests and Friends with Entity Framework Code First

  7. 7

    Entity Framework code first: How to ignore classes

  8. 8

    Entity Framework code first causes exception on database access

  9. 9

    How to use Entity Framework code-first with a newer database model version

  10. 10

    How to Keep Entity Framework Code First from using Derived Classes that Aren't Part of the Model

  11. 11

    Entity framework model first connection string how to change while moving code to server

  12. 12

    Error in Seed Method of Entity Framework, Tables not created in Code First Model

  13. 13

    Entity Framework 5 code first cannot get model to work

  14. 14

    Entity Framework 5 code first cannot get model to work

  15. 15

    Entity Framework 6 Code First: specific model design implementation

  16. 16

    BaseEntity in Entity Framework Model First

  17. 17

    entity framework code first migration working in EF5 but not in EF6

  18. 18

    Best way to use Entity Framework (Database First , Model First , Code First)

  19. 19

    How do I map a C# int to a SqlServer tinyint using Entity Framework Code First?

  20. 20

    WCF with Entity Framework Code First

  21. 21

    Entity Framework Inheritance Code First

  22. 22

    Relationships in Entity Framework Code First

  23. 23

    Entity Framework Code First connection

  24. 24

    Entity Framework Code First GenericTypeArguments

  25. 25

    WCF with Entity Framework Code First

  26. 26

    Entity Framework - Code First - Relationship

  27. 27

    Entity Framework Code First - Relationships

  28. 28

    Sample for Entity Framework 6 + Code First + Oracle 12c

  29. 29

    C# - Entity Framework - Large seed data code-first

HotTag

Archive