Associations in EF Code First: Part 2 – Complex Types

This is the second post in a series that explains entity association mappings with EF Code First. This series includes:

Introducing the Model

First, let's review the model that we are going to use in order to create a Complex Type with EF Code First. It's a simple object model which consists of two classes: User and Address. Each user could have one billing address (or nothing at all–note the multiplicities on the class diagram). The Address information of a User is modeled as a separate class as you can see in the class diagram below:
In object-modeling terms, this association is a kind of aggregation—a part-of relationship. Aggregation is a strong form of association; it has some additional semantics with regard to the lifecycle of objects. In this case, we have an even stronger form, composition, where the lifecycle of the part is fully dependent upon the lifecycle of the whole.

Fine-grained Domain Models

The motivation behind this design was to achieve Fine-grained domain models. In crude terms, fine-grained means more classes than tables. For example, a user may have both a billing address and a home address. In the database, you may have a single Users table with the columns BillingStreet, BillingCity, and BillingZipCode along with HomeStreet, HomeCity, and HomeZipCode. There are good reasons to use this somewhat denormalized relational model (performance, for one). In our object model, we can use the same approach, representing the two addresses as six string-valued properties of the User class. But it’s much better to model this using an Address class, where User has the BillingAddress and HomeAddress properties. This object model achieves improved cohesion and greater code reuse and is more understandable.

Complex Types are Objects with No Identity

When it comes to the actual C# implementation, there is no difference between this composition and other weaker styles of association but in the context of ORM, there is a big difference: A composed class is often a candidate Complex Type (aka Value Object). But C# has no concept of composition—a class or property can’t be marked as a composition. The only difference is the object identifier: a complex type has no individual identity (e.g. there is no AddressId defined on Address class) which make sense because when it comes to the database everything is going to be saved into one single table.

Complex Type Discovery

Code First has a concept of Complex Type Discovery that works based on a set of Conventions. The convention is that if Code First discovers a class where a primary key cannot be inferred, and no primary key is registered through Data Annotations or the fluent API, then the type will be automatically registered as a complex type. Complex type detection also requires that the type does not have properties that reference entity types (i.e. all the properties must be scalar types) and is not referenced from a collection property on another type.

How to Implement a Complex Type with EF Code First

The following shows the implementation of the introduced model in Code First:
public class User
{
    public int UserId { getset; }
    public string Name { getset; }
    
    public Address Address { getset; }
}
 
public class Address
{
    public string Street { getset; }
    public string City { getset; }
    public string ZipCode { getset; }
}
 
public class Context : DbContext
{
    public DbSet<User> Users { getset; }
}
With code first, this is all of the code we need to write to create a complex type, we do not need to configure any additional database schema mapping information through Data Annotations or the fluent API.

Complex Types: Splitting a Table Across Multiple Types

The mapping result for this object model is as follows (Note how Code First prefixes the complex type's column names with the name of the complex type):

Complex Types are Required

As a limitation of EF in general, complex types are always considered required. To see this limitation in action, let's try to add a record to the Users table:
using (var context = new Context())
{
    User user = new User()
    {
        Name = "Morteza"
    };
 
    context.Users.Add(user);
    context.SaveChanges();
}
Surprisingly, this code throws a System.Data.UpdateException at runtime with this message:
Null value for non-nullable member. Member: 'Address'.
If we initialize the address object, the exception would go away and the user will be successfully saved into the database:
Now if we read back the inserted record from the database, EF will return an Address object with Null values on all of its properties (Street, City and ZipCode). This means that even when you store a complex type object with all null property values, EF still returns an initialized complex type when the owning entity (e.g. User) is retrieved from the database.

Explicitly Register a Type as Complex

You saw that in our model, we did not use any data annotation or fluent API code to designate the Address as a complex type, yet Code First detects it as a complex type based on Complex Type Discovery. But what if our domain model requires a new property like "Id" on Address class? This new Id property is just another scalar non-primary key property that represents let's say another piece of information about Address. Now Code First can (and will) infer a key and therefore marks Address as an entity that has its own mapping table unless we specify otherwise. This is where explicit complex type registration comes into play. There are two ways to register a type as complex:
  • Using Data Annotations
  • EF 4.1 introduces a new attribute in System.ComponentModel.DataAnnotations namespace called ComplexTypeAttribute. All we need to do is to place this attribute on our Address class:
    [ComplexType]
    public class Address
    {
        public string Id { getset; }
        public string Street { getset; }
        public string City { getset; }
        public string ZipCode { getset; }
    }
    This will keep Address as a complex type in our model despite its Id property.
  • Using Fluent API
  • Alternatively, we can use ComplexType generic method defined on DbModelBuilder class to register our Address type as complex:
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.ComplexType<Address>();
    }

    Best Practices When Working with Complex Types

    • Always Initialize the Complex Type:
    • Because of the problem we saw, I recommended always initialize the complex type inside its owning entity's constructor.
    • Add a Read Only Property to the Complex Type for Null Value Checking:
    • Defining a non-persistent read only property like HasValue will help to test for null values.
    • Consider Always Explicitly Registering a ComplexType:
    • Even if your class is automatically detected as a complex type by Code First, I still recommend to mark it with ComplexTypeAttribute. Not only that helps your object model to be more readable but also ensures that your complex types will stay as complex as your model evolves in your project. Of course if you have a domain layer then you should use the fluent API's ComplexType method instead since coupling your POCO domain model to the EntityFramework assembly (where ComplexTypeAttribute lives) is the last thing you want to do in your layered architecture!
    Therefore, our final object model will be:
    public class User
    {
        public User()
        {
            Address = new Address();
        }
     
        public int UserId { getset; }        
        public string Name { getset; }
            
        public Address Address { getset; }
    }
     
    [ComplexType]
    public class Address
    {
        public string Street { getset; }
        public string City { getset; }
        public string ZipCode { getset; }
     
        public bool HasValue
        {
            get
            {
                return (Street != null || ZipCode != null || City != null);
            }
        }
    }
    The interesting point is that we did not have to explicitly exclude the HasValue property from the mapping above. Since HasValue has been defined as a read only property (i.e. there is no setter), EF Code First will be ignoring it based on conventions, which makes sense since a read only property is most probably representing a computed value and does not need to be persisted in the database.

    Customize Complex Type's Property Mappings at Entity Level

    We can customize the individual property mappings of the complex type. For example, The Users table now contains, among others, the columns Address_Street, Address_PostalCode, and Address_City. We can rename these with ColumnAttribute:
    public class Address
    {
        [Column("Street")]
        public string Street { getset; }
        public string City { getset; }        
        public string PostalCode { getset; }
    }
    Fluent API can give us the same result as well:
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.ComplexType<Address>()
                    .Property(a => a.Street)
                    .HasColumnName("Street");        
    }
    Any other entity table that contains complex type fields (say, a Customer class that also has an Address) uses the same column options. Sometimes we’ll want to override the settings we made inside the complex type from outside for a particular entity. This is often the case when we try to derive an object model from a legacy database. For example, here is how we can rename the Address columns for Customer class:
    public class User
    {
        public int UserId { getset; }
        public string Name { getset; }
     
        public Address Address { getset; }
    }
        
    public class Customer
    {
        public int CustomerId { getset; }
        public string PhoneNumber { getset; }
                
        public Address Address { getset; }
    }
     
    [ComplexType]
    public class Address
    {
        [Column("Street")]
        public string Street { getset; }
        public string City { getset; }
        public string ZipCode { getset; }
    }
        
    public class Context : DbContext
    {
        public DbSet<User> Users { getset; }
        public DbSet<Customer> Customers { getset; }
     
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Customer>()
                        .Property(c => c.Address.Street)
                        .HasColumnName("Customer_Street");
        }
    }

    Complex Types and the New Change Tracking API

    As part of the new DbContext API, EF 4.1 came with a new set of change tracking API that enables us to access Original and Current values of our entities. The Original Values are the values the entity had when it was queried from the database. The Current Values are the values the entity has now. This feature also fully supports complex types.

    The entry point for accessing the new change tracking API is DbContext's Entry method which returns an object of type DbEntityEntry. DbEntityEntry contains a ComplexProperty method that returns a DbComplexPropertyEntry object where we can access the original and current values:
    using (var context = new Context())
    {
        var user = context.Users.Find(1);
     
        Address originalValues = context.Entry(user)
                                        .ComplexProperty(u => u.Address)
                                        .OriginalValue;    
        
        Address currentValues = context.Entry(user)
                                       .ComplexProperty(u => u.Address)
                                       .CurrentValue;
    }
    Also we can drill down into the complex object and read or set properties of it using chained calls:
    string city = context.Entry(user)
                         .ComplexProperty(u => u.Address)
                         .Property(a => a.City)
                         .CurrentValue;
    We can even get the nested properties using a single lambda expression:
    string city = context.Entry(user)
                         .Property(u => u.Address.City)
                         .CurrentValue;

    Limitations of This Mapping 

    There are three important limitations to classes mapped as Complex Types:
  • Shared References is Not Possible:
  • The Address Complex Type doesn’t have its own database identity (primary key) and so can’t be referred to by any object other than the containing instance of User (e.g. a Shipping class that also needs to reference the same User Address, cannot do so).
  • No Elegant Way to Represent a Null Reference:
  • As we saw there is no elegant way to represent a null reference to an Address. When reading from database, EF Code First always initialize Address object even if values in all mapped columns of the complex type are null.
  • Lazy Loading of Complex Types is Not Possible:
  • Note that EF always initializes the property values of a complex type right away, when the entity instance that holds the complex object is loaded. EF does not support lazy loading for complex types (same limitation also exists if you want to have lazy loading for scalar properties of an entity). This is inconvenient when we have to deal with potentially large values (for example, a property of type byte[] on the Address complex type which has been mapped to a VARBINARY column on Users table and holds an image of the location described by the Address.).

    Summary

    In this post we learned about fine-grained domain models which complex type is just one example of it. Fine-grained is fully supported by EF Code First and is known as the most important requirement for a rich domain model. Complex type is usually the simplest way to represent one-to-one relationships and because the lifecycle is almost always dependent in such a case, it’s either an aggregation or a composition in UML. In the next posts we will revisit the same domain model and will learn about other ways to map a one-to-one association that does not have the limitations of the complex types.

    References

    Published Monday, March 28, 2011 9:13 PM by mortezam

    Comments

    # re: Associations in EF 4.1 Code First: Part 2 – Complex Types

    Friday, April 8, 2011 4:35 AM by anonym

    thanks for this great article

    # re: Associations in EF 4.1 Code First: Part 2 – Complex Types

    Wednesday, April 13, 2011 5:51 PM by Frank

    Hi, I am hoping you can help me out. My scenario is as follows:

    I have existing tables from the aspnet db and one of the tables is aspnet_Membership. It has a column called UserId. I created another (one of my own) table called Users where I want a one-to-one relationship with the aspnet_Membership table by UserId as the key.

    [I create my own initializer that deletes and recreates tables based on a naming convention so the aspnet tables don't get touched]

    My User domain object contains below properties as I want to retrieve some info from the aspnet_Membership as well:

    public Guid UserId { get; set; }

    public virtual aspnet_Membership aspnet_Membership { get; set; }

    My mapping is:

    HasKey(u => u.UserId).HasRequired(u => u.aspnet_Membership);

    UserId column is the primary key and I also get aspnet_Membership_UserId as the FK.

    Whenever I write user.aspnet_Membership.Email == "x" the join is by the FK aspnet_Membership_UserId and not UserId (user.aspnet_Membership_UserId = aspnet_Membership.UserId)

    The right hand side is correct but the left I want by UserId and not aspnet_Membership_UserId.

    Please help me out. I've been banging on this for 2 days.

    # re: Associations in EF 4.1 Code First: Part 2 – Complex Types

    Wednesday, April 27, 2011 5:33 AM by Nekketsu

    public Address Address { get; set; }

    Why not use the mapping prefix name the name of variable "Address" instead of the name of type (in this case the same, "Address")? It could allow programmer to easyly use the prefix name he prefers:

    public Address DeliveryAddress { get; set; }

    public Address Address { get; set; }

    It could generate:

    DeliveryAddress_Street

    DeliveryAddress_City

    DeliveryAddress_ZipCode

    Address_Street

    Address_City

    Address_ZipCode

    # re: Associations in EF 4.1 Code First: Part 2 – Complex Types

    Wednesday, April 27, 2011 11:39 AM by Tester

    How can I have a list of ComplexTypes in an entity

    eg :

    ------------------------------------------

    class Blog
    {
        public int Id { get;set;}
        public string Title { get;set;}
        public List<Tag> Tags {get;set; }
    }

    [ComplexType]
    class Tag
    {
        int Id {get;set;}
        string Name { get;set;}
    }

    public class Context : DbContext
    {
        DbSet<Tag> Tags { get;set; }
        DbSet<Blog> Blogs{get;set;}               
    }

    # re: Associations in EF 4.1 Code First: Part 2 – Complex Types

    Wednesday, April 27, 2011 12:45 PM by mortezam
    @Tester: You can’t. Think about it, if you define a collection of Tags on the Blog entity, it means that the Tag entity should somehow maintain a BlogId in the Tags table to establish the one-to-many relationship between Blog and Tag entities, however, when you mark Tag class as a complex type then there won’t be a Tags table as everything related to Tag class are embedded into the Blogs table. That’s why I strictly explained Complex Types in the context of a one-to-one association. If you have such a requirement, then you should let Tag to be an entity and then create a one-to-many association between the two. Please let me know if you need help for doing so. Hope this helps :)

    # re: Associations in EF 4.1 Code First: Part 2 – Complex Types

    Wednesday, April 27, 2011 1:33 PM by mortezam
    @Nekketsu: I’m aware that you’ve been looking for this feature since the CTP5 build and unfortunately I don’t have a better answer than the one I provided on the other post since Pluggable Conventions has been removed from the EF 4.1 release. Back to your question, prefixing the complex type columns with the name of the type is more useful in scenarios that you only have one property of a particular complex type on an entity while prefixing it with the name of the property itself is better when you have multiple properties of a complex type like your example. Having said that, I think their decision by prefixing it to the type is correct since it’s just a convention and it should favor the case that happens more often. I think you agree that most of the times we only have one property of a particular complex type on our entities since we usually create a one-to-many relationship if it’s more than one. In the next release we (hopefully) would be able to change this convention using Pluggable Conventions.

    # re: Associations in EF 4.1 Code First: Part 2 – Complex Types

    Tuesday, October 11, 2011 1:41 PM by Alexander Leventsov

    Is it possible mapping the inheritance of complex types, but Celsius and Fahreihegt used TPH mapping:

    [ComplexType]
    public class Unit
    {
        public double Value { get; set; }
    }

    public class Celsius : Unit
    {
        [NotMapped]
        public double Degrees { get { return this.Value; } }
    }

    public class Fahrenheit : Unit
    {
        [NotMapped]
        public double Degrees { get { return this.Value; } }
    }

    [Table("Measurements")]
    public class Measurement
    {
        [Key]
        long Id { get; set; }
        Unit Value { get; set; }
        DateTime Time { get; set; }
    }

    public class NamedParameter
    {
        [Key]
        int Id { get; set; }
        string Name { get; set; }
        Unit Value { get; set; }
    }

    Important for me inherit different childs types Celsius, Pascal, Meter .. from Unit,

    on the other hand it is important to mapped "Time" column and "Value" column to one table "Measurements"

    If this is not possible, then maybe there's another way?

    # re: Associations in EF Code First: Part 2 – Complex Types

    Saturday, July 14, 2012 7:01 PM by Mohamoud

    THANKS for this GREAT and Consice explenation of the Complex Types in EF 4.

    I had a notation that Complex Types is how EF 4 (code first) supports the concept of ValueObjects in DDD and your Article have re-enforced my thinking. Actually, am I correct to state that the points listed under the "Limitations of This Mapping " section are not limitations per se, but rather, it's  how EF 4x supports developers who are doing  DDD modeling?

    Thanks again and looking forward reading the rest of the articles!

    # re: Associations in EF Code First: Part 2 – Complex Types

    Tuesday, April 23, 2013 9:25 PM by MaMcmichael

    Keep on working, great job!