entity-frameworkef-code-firstknockout.jsknockout-2.0upshot

How to Bind multiple properties of one class to another using Entity Framework (EF) 4.1 Code First for use with Upshot.js?


I have a scenario where I need to bind two properties from one class to another class using Entity Framework 4.1 Code-First. (For reference, this model is being consumed by Upshot.js for use in a single page application using Knockout.js 2.1)

Normally, I would have done something like the following:

    public class Person
    {
        [Key]
        public int PersonId { get; set; }

        public string FirstName { get; set; }
        public string LastName { get; set; }

        public Address HomeAddress { get; set; }
        public Address OfficeAddress { get; set; } 
    }

    public class Address
    {
        [Key]
        public int AddressId { get; set; }

        public string StreetAddress { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string ZipCode { get; set; }
    }

This allows HomeAddress and OfficeAddress to both reference an instance of the Address class.

Please note this is not my real data model. It is for illustrative purposes only. In real life, I probably would have used an ICollection. Unfortunately, it is not feasible for this particular situation, and I do need to maintain multiple references from one class to another.

In this particular scenario, it is also possible for a person to exist without any addresses defined. It is also possible for addresses to exist without a person. (As mentioned, this data model is just an example.)

While this compiles correctly, and I can even create and save data, upshot complains bitterly when it attempted to use this model.

It gives an (inner) exception like the following:

{"Unable to retrieve association information for association 'KnockoutTest.Models.Person_HomeAddress'. Only models that include foreign key information are supported. See Entity Framework documentation for details on creating models that include foreign key information."}

So... I attempted to set the Foreign Key information on the DbContext class like

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()
    .HasOptional(m => m.HomeAddress);

    modelBuilder.Entity<Person>()
    .HasOptional(m => m.OfficeAddress);
}

No joy! This still gave me the same exception.

I am not sure how to set up the foreign key association so that multiple properties on one class can reference another class--at least not in a way that upshot will be pleased and stop complaining for a while.

What am I doing wrong, and how do I fix it?


Solution

  • You just have to introduce scalar foreign key properties into your model class:

    public class Person
    {
        [Key]
        public int PersonId { get; set; }
    
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        [ForeignKey("HomeAddress")]
        public int? HomeAddressId { get; set; }
        public Address HomeAddress { get; set; }
    
        [ForeignKey("OfficeAddress")]
        public int? OfficeAddressId { get; set; } 
        public Address OfficeAddress { get; set; } 
    }
    

    The properties must be nullable (int?) because your relationships are optional (person can exist without addresses).