Associations in EF Code First CTP5: Part 1 – Complex Types

Last week the CTP5 build of the new Entity Framework Code First has been released by data team at Microsoft. Entity Framework Code-First provides a pretty powerful code-centric way to work with the databases. When it comes to associations, it brings ultimate flexibility. I’m a big fan of the EF Code First approach and I am planning to explain association mapping with code first in a series of blog posts and this one is dedicated to Complex Types.

A Note For Those Who are New to Entity Framework and Code-First

If you choose to learn EF you've chosen well. If you choose to learn EF with Code First you've done even better. To get started, you can find a great walkthrough by Scott Guthrie here and another one by ADO.NET team here. In this post, I assume you already setup your machine to do Code First development and also that you are familiar with Code First fundamentals and basic concepts.

In order to build a solid foundation for our discussion, we will start by learning about some of the core concepts around the relationship mapping.  

What is Mapping?

Mapping is the act of determining how objects and their relationships are persisted in permanent data storage, in our case, relational databases.

What is Relationship Mapping?

A mapping that describes how to persist a relationship (association, aggregation, or composition) between two or more objects.

Types of Relationships

There are two categories of object relationships that we need to be concerned with when mapping associations. The first category is based on multiplicity and it includes three types:
  • One-to-one relationships: This is a relationship where the maximums of each of its multiplicities is one.
  • One-to-many relationships: Also known as a many-to-one relationship, this occurs when the maximum of one multiplicity is one and the other is greater than one.
  • Many-to-many relationships: This is a relationship where the maximum of both multiplicities is greater than one.
The second category is based on directionality and it contains two types:
  • Uni-directional relationships: when an object knows about the object(s) it is related to but the other object(s) do not know of the original object. To put this in EF terminology, when a navigation property exists only on one of the association ends and not on the both.
  • Bi-directional relationships: When the objects on both end of the relationship know of each other (i.e. a navigation property defined on both ends).

How Object Relationships are Implemented in POCO Object Models?

When the multiplicity is one (e.g. 0..1 or 1) the relationship is implemented by defining a navigation property that reference the other object (e.g. an Address property on User class). When the multiplicity is many (e.g. 0..*, 1..*) the relationship is implemented via an ICollection of the type of other object.

How Relational Database Relationships are Implemented?

Relationships in relational databases are maintained through the use of Foreign Keys. A foreign key is a data attribute(s) that appears in one table and must be the primary key or other candidate key in another table. With a one-to-one relationship the foreign key needs to be implemented by one of the tables. To implement a one-to-many relationship we implement a foreign key from the “one table” to the “many table”. We could also choose to implement a one-to-many relationship via an associative table (aka Join table), effectively making it a many-to-many relationship.

Introducing the Model

Now, let's review the model that we are going to use in order to implement Complex Type with Code First. It's a simple object model which consist of two classes: User and Address. Each user could have one billing address. The Address information of a User is modeled as a separate class as you can see in the UML model 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 User table with the columns BillingStreet, BillingCity, and BillingPostalCode along with HomeStreet, HomeCity, and HomePostalCode. 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: Splitting a Table Across Multiple Types

Back to our model, there is no difference between this composition and other weaker styles of association when it comes to the actual C# implementation. But in the context of ORM, there is a big difference: A composed class is often a candidate Complex Type. 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 (i.e. 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.

How to implement a Complex Type with Code First

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. Here is the implementation:
public class User
{
    public int UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Username { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }       
    public string PostalCode { get; set; }       
}

public class EntityMappingContext : DbContext
{
    public DbSet<User> Users { get; set; }       
}

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.

Database Schema

The mapping result for this object model is as follows:

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 our database:
using (var context = new EntityMappingContext())
{
    User user = new User()
    {
        FirstName = "Morteza",
        LastName  = "Manavi",
        Username  = "mmanavi"        
    };
 
    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 user will be successfully saved into database:
When we read back the inserted record from the database, EF will return an Address object with all the properties (Street, City and PostalCode) have null values. This means that if you store a complex type object with all null property values, EF returns a initialized complex type when the owning entity 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 perfectly detects it as a complex type based on Complex Type Discovery concept. But what if our domain model requires a new property called Id on Address class? This new Id property is just a scalar non-primary key property that represents let's say another piece of information about address. In this case, Code First actually can 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. CTP5 defined a new attribute in System.ComponentModel.DataAnnotations namespace called ComplexTypeAttribute. All we need to do is to use this attribute on our Address class:
[ComplexType]
public class Address
{
    public int Id { getset; }
    public string Street { getset; }
    public string City { getset; }
    public string PostalCode { getset; }
}
This will cause Address to remain as a complex type in our model. As always, we can do the same with fluent API. In CTP5 a new generic method has been added to ModelBuilder class which is called ComplexType and has the following signature (when working with fluent API, we don't really care about the method's return values):
public virtual ComplexTypeConfiguration<TComplexType> ComplexType<TComplexType>() 
                                        where TComplexType : class;
Here is how we can register our Address type as complex in fluent API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ComplexType<Address>();
}

Best Practices When Working with Complex Types

  • Always initialize the complex type: Because of the problem we just saw, I recommended to 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 using ComplexType attribute: Even if your class is automatically detected as a complex type by Code First, I still recommend to mark it with [ComplexType] attribute. Not only that helps your object model to be more readable but also ensures that your complex types will stay as complex type as your model evolves in your project. Furthermore, there is a bug in CTP5 and that is if you put Required attribute (a data annotation that Code First supports for validation) on any of the complex type's properties (e.g. PostalCode) then Code First will stop thinking that it is a complex type and will throw a ModelValidationException. The workaround for this bug is to explicitly mark Address with ComplexType attribute. Hence, it will be beneficial in such cases as well.
Therefore, our final object model will be:
public class User
{
    public User()
    {
        Address = new Address();
    }
 
    public int UserId { getset; }
    public string FirstName { getset; }
    public string LastName { getset; }
    public string Username { getset; }
    public Address Address { getset; }
}
 
[ComplexType]
public class Address
{
    public string Street { getset; }
    public string City { getset; }
    public string PostalCode { getset; }
        
    public bool HasValue 
    {
        get
        {
            return (Street != null || PostalCode != null || City != null);
        }
    }
}
The interesting point is that we do not have to explicitly exclude HasValue property from the mapping. Since this property does not have a setter, EF Code First will be ignoring it based on a convention which makes sense since a read only property is most probably represents a computed value and does not need to be persist in the database.

Complex Types and the New Change Tracking API

EF Code First CTP5 exposes a new set of change tracking information that enables us to access Original, Current & Stored values, and State (e.g. Added, Unchanged, Modified, Deleted) 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:
using (var context = new EntityMappingContext())
{
    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;
}
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:
namespace System.Data.Entity.Infrastructure
{    
    public class DbEntityEntry<TEntity> where TEntity : class
    {       
        public DbComplexPropertyEntry<TEntity, TComplexProperty> 
            ComplexProperty<TComplexProperty>
                (Expression<Func<TEntity, TComplexProperty>> property);
    }
}

Limitations of This Mapping

There are two 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).
  • 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.

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 Saturday, December 11, 2010 8:21 AM by mortezam

Comments

# re: Entity Association Mapping with Code First Part 1 : Mapping Complex Types

Sunday, December 12, 2010 12:22 PM by ali62b

Very useful post. Keep up the great work !

# re: Entity Association Mapping with Code First Part 1 : Mapping Complex Types

Sunday, December 12, 2010 6:57 PM by Paul

Great read! Cannot wait to read the rest of this series.

# re: Entity Association Mapping with Code First Part 1 : Mapping Complex Types

Monday, December 13, 2010 6:30 AM by HariOm

hmm..

I create applications using an EF that I created myself.

Never bothered to track what Microsoft is doing with their EF.

Anyway, mine doesnt even need the code to be typed in.

Also, a query. In the above example, how does the EF track change in Address of the User.

Since it is normalised, how does one retrieve the old Address for a given User once the Address object is updated.

# re: Entity Association Mapping with Code First Part 1 : Mapping Complex Types

Tuesday, December 14, 2010 2:11 PM by mortezam
@HariOm: EF  keeps track of the original and current values for every entity. The original values are the values the entity had when it was queried from the database.  The current values are the ones the entity has now.  EF doesn’t keep track of any more history than this. Therefore, you can access the old Address values for a given User by reading its original values. I just updated the post to show how it is done by using the new change tracking API when it comes to Complex Types.  Thanks for your great question :)

# re: Entity Association Mapping with Code First Part 1 : Mapping Complex Types

Tuesday, December 14, 2010 8:45 PM by Yuvan

How do I add validation via dataannotation.When I try adding a Required Validation on PostalCode Property it breaks and throws an error.However when I add a Regular expression validation on that property it works.Is this a bug in the CTP5??

# re: Entity Association Mapping with Code First Part 1 : Mapping Complex Types

Wednesday, December 15, 2010 12:00 AM by Paul

Great additions, was not aware of the Entry() method. Learn something new everyday!

# re: Entity Association Mapping with Code First Part 1: Complex Types

Sunday, December 19, 2010 10:11 PM by mortezam
@Yuvan: Yes, I checked this with EF team, this is a bug in CTP5. Putting [Required] on a property of the complex type should not cause Code First to stop thinking that it is a complex type. The exception that you are getting would go away if you explicitly mark Address class with [ComplexType] attribute. Thanks :)

# re: Entity Association Mapping with Code First Part 1: Complex Types

Tuesday, December 21, 2010 5:59 AM by BatsIhor

Thank, very nice explanation, I am learning EF4CF and this series really help me!

# re: Entity Association Mapping with Code First Part 1: Complex Types

Tuesday, December 21, 2010 9:01 AM by anonymous

If I have
Person
{
  Id
  Name
  ContactInfo
}
ContactInfo
{
  Phone
  Address
}
Address
{
 city
}
it will be 2 complex types ( ContactInfo and Address )
This logic is not working with ctp5 and says ( and if only contactInfo it is working )
The server encountered an error processing the request. The exception message is 'One or more validation errors were detected during model generation: System.Data.Edm.EdmEntityType: : EntityType 'ContactInfo' has no key defined. Define the key for this EntityType. System.Data.Edm.EdmEntitySet: EntityType: The EntitySet ContactInfoes is based on type ContactInfo that has no keys defined. '. See server logs for more details. The exception stack trace is:

# re: Entity Association Mapping with Code First Part 1: Complex Types

Tuesday, December 21, 2010 9:08 AM by Anonymous

Sorry. The above code will work if we do the constructor with creation of ComplexTypes in the constructor thingy:
Person
{
  Id
  Name
  ContactInfo
   public Person()
  {
     contactInfo=new ContactInfo();
  }
}
similarly for ContactInfo and Address ( create Address in ContactInfo constructor )

# re: Entity Association Mapping with Code First Part 1: Complex Types

Wednesday, December 22, 2010 6:24 PM by Frank

By the way, excellent stuff. I have a class User which has ICollection<Token> and ICollection<Role>. User to Tokens is 1..many. User to Roles table is many..many. My mapping is (probably wrong):

HasKey(u => u.UserId).HasOptional(u => u.Tokens).WithRequired().WillCascadeOnDelete();

HasMany(u => u.Roles).WithMany(r => r.Users);

When I create a new User, in its ctor I instantiate a new List of Tokens and then simply add a new Token class to that collection later as User.Tokens.Add(some_token) and I get:

"Unable to cast object of type 'System.Collections.Generic.List`1[Token]' to type 'Token'."

Any help is appreciated.

# re: Entity Association Mapping with Code First Part 1: Complex Types

Wednesday, December 22, 2010 8:21 PM by mortezam
@Frank: The reason you are getting the exception is because the fluent API code for User-Token association is incorrect. That code is good for a one-to-one association while the association is one-to-many (like you mentioned). The following will do the trick:

public class User
{
    public User()
    {
        Tokens = new List<Token>();
        Roles = new List<Role>();
    }
    public int UserId { get; set; }
    public virtual ICollection<Token> Tokens { get; set; }
    public virtual ICollection<Role> Roles { get; set; }
}

public class Token
{
    public int TokenId { get; set; }
}

[Table("Role")]
public class Role
{
    public int RoleId { get; set; }
    public int RoleTypeId { get; set; }
    public virtual ICollection<User> Users { get; set; }
    public virtual RoleType RoleType { get; set; }
}

public class RoleType
{
    public int RoleTypeId { get; set; }
    public string RoleName { get; set; }
}

public class CTP5Context : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Token> Tokens { get; set; }
    public DbSet<Role> Roles { get; set; }
    public DbSet<RoleType> RoleType { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 1:* between User and Token:
        modelBuilder.Entity<User>().HasMany(u => u.Tokens).WithRequired().WillCascadeOnDelete();
           
        // *:* between User and Role
        modelBuilder.Entity<User>().HasMany(u => u.Roles).WithMany(r => r.Users).Map(m =>
        {
            m.ToTable("Roles");
        });
    }
}

Please note that I've not use any fluent API code to designate UserId as a key for User entity. This will be configured automatically by Code First based on the convention. Now, if you run your code that adds a new User object with a Token against this object model, you’ll see that it will successfully save into the database. I’ll fully explain one-to-many and many-to-many associations in my next posts in this series. Thanks :)

# re: Entity Association Mapping with Entity Framework Code First CTP5 Part 1: Complex Types

Thursday, December 23, 2010 12:24 PM by Frank

Perfect. So for the roles, I'm trying to have a table called Roles that has RoleId and UserId, the actual role name should be in a separate table called RoleTypes with RoleId and Name.

1) How do you set that up?

2) At what point do I insert static values for the role types. Say my app needs 5 roles which are always static. How would you configure this.

Thank you again.

# re: Entity Association Mapping with Entity Framework Code First CTP5 Part 1: Complex Types

Thursday, December 23, 2010 1:10 PM by Frank

Looks like my original is working where I have HasMany(u => u.Roles).WithMany(r => r.Users). The only issue is when I create a new user twice with the same role, I do

User user = new User()

user.Roles.Add(new Role() { Name = "RoleX" }

User user = new User()

user.Roles.Add(new Role() { Name = "RoleX" }

I need the Roles table to have one row for RoleX and have UserRoles to have two rows pointing to the same RoleId. Roles should be a static table with RoleX as a unique value.

# re: Entity Association Mapping with Entity Framework Code First CTP5 Part 1: Complex Types

Saturday, December 25, 2010 11:12 AM by mortezam
@Frank: I've updated the object model above and now it handles all your requirements. Please note that the only reason I’ve started using fluent API for the many-to-many association between User and Role is to customize the join table’s name to be “Roles”. For that I also had to change the name of the table for Role entity to avoid name collision. In addition, the following code snippet shows how you can add multiple Users for a particular Role which the Role is new as well:

using (var context = new CTP5Context())
{
    RoleType roleType = context.RoleType.Single(rt => rt.RoleName.Equals("Role1"));
    Role role = new Role()
    {
        RoleType = roleType
    };                                

    User user1 = new User();
    user1.Roles.Add(role);                
    User user2 = new User();               
    user2.Roles.Add(role);

    context.Users.Add(user1);
    context.Users.Add(user2); 
    context.SaveChanges();
}

Regarding to your first question, as you can see in the object model above, I set up a one-to-one foreign key association between RoleType and Role entities. About your second question, probably the best way to populate RoleTypes table is to override the Seed() method:

public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<CTP5Context>
{
    protected override void Seed(CTP5Context context)
    {
        RoleType roleType = new RoleType()
        {
            RoleName = "Role1"
        };
        context.RoleType.Add(roleType);
        context.SaveChanges();

        int result1 = context.Database.SqlCommand("ALTER TABLE Role ADD CONSTRAINT uc_RoleTypeId UNIQUE(RoleTypeId)");
        int result2 = context.Database.SqlCommand("ALTER TABLE RoleTypes ADD CONSTRAINT uc_RoleName UNIQUE(RoleName)");
    }
}

I also want to point out that in the Seed method, I took advantage of the new CTP5’s SqlCommand method on DbContext.Database which allows raw SQL commands to be executed against the database. Using that, I defined a unique constraint on RoleName column in RoleTypes table as per your requirement and also another one on RoleTypeId FK in Role table to make sure that the relationship between Role and RoleType will be remained as one-to-one. Hope this helps :)

# re: Entity Association Mapping with Entity Framework Code First CTP5 Part 1: Complex Types

Sunday, December 26, 2010 10:56 PM by Frank

Thank you for taking the time to do this. I appreciate it. The only problem I have is the manual SqlCommand logic. To me, a big benefit with CF is the ability to switch out to another db fast. With manual SqlCommand stuff, it is now tightly coupled to SQL Server. Just wondering if there's a better approach.

# re: Entity Association Mapping with Entity Framework Code First CTP5 Part 1: Complex Types

Monday, December 27, 2010 12:01 PM by Frank

Another point. Would a TPH scenario work better may be? I was thinking may be create an

AdminRole : Role that doesn't add any additional properties but then the discriminator would act as the key of what type of role the user would have. Thoughts about my two comments?

# re: Entity Association Mapping with Entity Framework Code First CTP5 Part 1: Complex Types

Monday, December 27, 2010 3:51 PM by mortezam
@Frank: The reason that I put the code for creating unique constraints in the Seed method is because CTP5 (and EF in general) does not natively support one-to-one FK associations. It’s likely to be supported in the next RTM and until then, you can manually add the constraints to your DB if you don’t like the idea of doing it with SqlCommand method.
Regarding your second point, I don’t think introducing inheritance in this scenario would be a good idea because defining 5 new subclasses inheriting from Role class without introducing any specialized attribute or behavior is a bit overkill and also won’t scale well (e.g. consider a scenario that you want to add more RoleTypes in the future). In addition, by using TPH (or any other inheritance mapping strategy for that matter) you are technically introducing polymorphic associations (an association to a base class, hence to all classes in the hierarchy with dynamic resolution of the concrete class at runtime) in your object model. In other words, User will have a polymorphic association to an abstract Role class. The dynamic resolution of the Role Type at runtime means a more complex query being sent to the database and also more work at the time of object materialization which both come with a bit of performance penalty. Polymorphic association is an important topic and I’ll explain it in a separate post once I finish my inheritance mapping strategies series. Hope this helps :)

# re: Entity Association Mapping with Entity Framework Code First CTP5: Part 1 – Complex Types

Friday, December 31, 2010 11:21 AM by Andrew

Excellent post and also some very helpful comments here.  Keep it up!

# re: Entity Association Mapping with Entity Framework Code First CTP5: Part 1 – Complex Types

Tuesday, January 4, 2011 11:22 AM by Daniel

Excellent post!  I am new to EF code first and have been banging my head against the wall trying to setup a relationship between four tables without putting data in all the tables every time I need to update one table.  I think complex types is what I have been missing.  Please keep up the good work.  This is highly appreciated.

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

Monday, January 24, 2011 7:40 PM by milanCHE

Thx, for the great post! The only problem I have is to set complex type as primary key in code first development. For example Key has Id, Name, RepositoryName and TypeName and every strong object has key. Help please!

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

Monday, January 24, 2011 11:33 PM by mortezam
@milanCHE: Complex Types are not meant to be used in this scenario and they wouldn’t be able to handle that. Like I said in the post they are only for mapping a special type of one-to-one association (i.e. composition) between objects, period. If your intention by doing that is to reuse the key properties instead of repeating them in every single entity, then I recommend using inheritance instead of a complex type in your object model. That inheritance would be best represented by a Table per Concrete Type (TPC) strategy. For example, consider the following implementation for your scenario:

public abstract class EntityBase
{       
    public int Id { get; set; }
    public string Name { get; set; }
    public string RepositoryName { get; set; }
    public string TypeName { get; set; }
}

public class User : EntityBase
{       
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Username { get; set; }       
}

public class Address : EntityBase
{
    public string Street { get; set; }
    public string City { get; set; }
    public string PostalCode { get; set; }
}

public class EntityMappingContext : DbContext
{
    public DbSet<EntityBase> Entities { get; set; }       

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<EntityBase>().HasKey(e => new
        {
            e.Id,
            e.Name,
            e.RepositoryName,
            e.TypeName
        });
                       
        modelBuilder.Entity<User>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("Users");
        });

        modelBuilder.Entity<Address>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("Addresses");
        });
    }
}

As a result every concrete subclass will end up having their own table with key columns defined in EntityBase. Hope this helps :)

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

Tuesday, January 25, 2011 6:50 AM by MIlanCHE

Thanks for the response, very much.

I need this for passing keys, for example in XAML

{Binding Key}

But I can extend EntityBase with read only Key property

public abstract class EntityBase
{       
    ...

    [NotMapped]
    public Key Key
    {
        get { return this;}
    }

    public static implicit operator Key(EntityBase input)
    {
        Key k = new Key();
        k.Id = input.Id;
        k.Name = input.Name;
        k.TypeName = input.TypeName;
        k.RepositoryName = input.RepositoryName;
        return k;
    }

I have one questions for now, if you do not mind:

If I want to implement week reference for association as Complex type, for example:

public class Reference<T> where T : EntityBase
{
    public Reference(T input)
    {
        this.Id = input.Id;
        this.Name = input.Name;
        this.TypeName = input.TypeName;
        this.RepositoryName = input.RepositoryName;
        Value = input;
    }

   public string Id { get; set; }
   public string Name { get; set; }
   public string TypeName { get; set; }
   public string RepositoryName { get; set; }

   [XmlIgnore][NotMapped]
   public T Value {get;set;}
}

public class User : EntityBase
{       
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string Username { get; set; }
   public Reference<Address> Address{ get; set; }
}

public class Address : EntityBase
{
   public string Street { get; set; }
   public string City { get; set; }
   public string PostalCode { get; set; }
}

How to configure this, but in db to get table for User, with columns :

   Id
   Name
   TypeName
   RepositoryName
   FirstName
   LastName
   Username
   Address_Id
   Address_Name
   Address_TypeName
   Address_RepositoryName

Once again I appreciate your help and the time you have spent posting these articles. They are a HUGE help for me.

Milan

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

Thursday, February 17, 2011 4:43 AM by Nekketsu

Is it posible to automatically prefix complex types table name with the name of variable instead of name of type? I mean:

public class User
{
    Address DeliveryAddress;
    Address HomeAddress;
}

And I want to generate automatically the names for table fields:

 DeliveryAddress_Street
 DeliveryAddress_City
 DeliveryAddress_PostalCode
 HomeAddress_Street
 HomeAddress_City
 HomeAddress_PostalCode

Thank you!

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

Thursday, February 17, 2011 12:33 PM by mortezam
@Nekketsu: For now this can be achieved by using fluent API:

public class EntityMappingContext : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new UserConfiguration());
    }
}

class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {
        Property(u => u.DeliveryAddress.Street).HasColumnName("DeliveryAddress_Street");
        Property(u => u.DeliveryAddress.City).HasColumnName("DeliveryAddress_City");
        Property(u => u.DeliveryAddress.PostalCode).HasColumnName("DeliveryAddress_PostalCode");

        Property(u => u.HomeAddress.Street).HasColumnName("HomeAddress_Street");
        Property(u => u.HomeAddress.City).HasColumnName("HomeAddress_City");
        Property(u => u.HomeAddress.PostalCode).HasColumnName("HomeAddress_PostalCode");
    }
}

I realize that this code is not very elegant and could become tedious and buggy if there are so many complex types out there. The EF team is looking into ways to enable us achieving this with Pluggable Conventions but they are still very early in the implementation process. Hope this helps.

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

Friday, February 18, 2011 1:35 AM by Jack

How is it that the complex type column naming (as per your comment directly prior) used to work just fine in CTP4? And now its broken?

It really destroys faith in the EF team when things constantly regress.

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

Friday, February 18, 2011 11:21 AM by mortezam
@Jack: I admit that CTP4 had a better naming convention when it comes to complex type’s column names and I understand the source of your frustration in this regard, however, you should also take this into account that these are merely CTPs and being released just to get an early feedback during development. Therefore, it is normal that the API get changed from time to time as it is not final yet. In the case of CTP5, they did some large refactoring on the relationship API and they didn't re-enable everything in time for CTP5 so you can find few inconsistencies and limitations comparing to CTP4.

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

Friday, April 15, 2011 5:12 PM by ryanse

If you are interested in using the Entity Framework with Domain Driven Design, checkout my new "Domain Driver" framework on CodePlex.

This framework provides developers with a way to quickly and easily implement a full domain model, to test that domain model using pre-built generic tests, and to prototype user-inferface components against that domain model to help achieve customer validation. Initially, the domain model will function as an in-memory database, but at any point developers can add the ability to persist to a database, a file, or any other non-volatile data store.

Domain Driver itself is decoupled from any persistence technology, but I implemented an example that clearly shows how to use it with EF Code-First to accomplish Database persistence.

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

Wednesday, May 18, 2011 8:32 AM by dencio

Thanks. Great post.

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

Thursday, October 6, 2011 3:03 AM by Jviaches

Great post ! Simple and clear explain regarding Code First approach.

Thank you!

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

Friday, October 19, 2012 3:46 PM by Naom

Hi,

I have the Client table in the database that stores information about two contacts in these columns

Contact1, Email1, Phone1, Ext1 and Contact2, Email2, Phone2, Ext2

So, I had my Client class originally designed this way:

public class Client

   {        

       [Key]

       [Column("ClientId",TypeName = "int")]

       public virtual int Id { get; set; }

       [Required]

       [DisplayName("Client No")]

       [Column("client_no", TypeName = "smallint")]

       public virtual Int16 Number { get; set; }

       [Required]

       [Column("client_name", TypeName = "varchar")]

       [DisplayName("Client Name")]

       [MaxLength(30, ErrorMessage = "Client Name should not be longer than 30 characters" )]

       [MinLength(3, ErrorMessage = "Client Name is too short")]

       public virtual string Name { get; set; }

       [StringLength(100)]

       [DisplayName("First Contact")]

       [DisplayFormat(NullDisplayText = "")]

       [Column("Contact1",TypeName =  "varchar")]

       public virtual string Contact1 { get; set; }

       [Email]

       [StringLength(100)]

       [Column("c1_email", TypeName = "varchar")]

       public virtual string Email1 { get; set; }

       [DataType(DataType.PhoneNumber)]

       [Column("C1_Phone", TypeName = "varchar")]

       [StringLength(10)]

       [DisplayName("Phone")]

       public virtual string Phone1 { get; set; }

       [StringLength(5)]

       [Column("C1_Ext", TypeName = "varchar")]

       [DisplayName("Ext")]

       public virtual string Ext1 { get; set; }

       [StringLength(100)]

       [DisplayName("Second Contact")]

       [Column("Contact2", TypeName = "varchar")]

       public virtual string Contact2 { get; set; }

       [Email]

       [StringLength(100)]

       [Column("C2_Email", TypeName = "varchar")]

       public virtual string Email2 { get; set; }

       [DataType(DataType.PhoneNumber)]

       [StringLength(10)]

       [DisplayName("Phone")]

       [Column("C2_Phone", TypeName = "varchar")]

       public virtual string Phone2 { get; set; }

       [StringLength(5)]

       [DisplayName("Ext")]

       [Column("C2_Ext",TypeName = "varchar")]

       public virtual string Ext2 { get; set; }

       [DataType(DataType.MultilineText)]

       public virtual string Address { get; set; }

       [ForeignKey("EnteredByOperator")]

       public string EnteredBy { get; set; }

       [InverseProperty("ClientsEnteredBy")]

       public virtual Operator EnteredByOperator { get; set; }

       [ForeignKey("ModifiedByOperator")]

       public string ModifiedBy { get; set; }

       [InverseProperty("ClientsUpdatedBy")]

       public virtual Operator ModifiedByOperator { get; set; }

       [DataType(DataType.DateTime)]

       [DisplayName("Created on")]

       public DateTime EnteredOn { get; set; }

       [DataType(DataType.DateTime)]

       [DisplayName("Modified on")]

       public DateTime? ModifiedOn { get; set; }

       public virtual ICollection<ClientOrder> ClientOrders { get; set; }

       public virtual ICollection<Reorder> Reorders { get; set; }

   }

}

I want to re-factor it and use ContactDetail class and also a sub-class PhoneInfo (to combine Phone and Ext).

So, I added these two new classes:

[ComplexType]

   public class PhoneInfo

   {

       [DataType(DataType.PhoneNumber)]

       [StringLength(10)]

       [DisplayName("Phone")]

       public virtual string Phone { get; set; }

       [StringLength(5)]

       [DisplayName("Ext")]

       public virtual string Ext { get; set; }

   }

   [ComplexType]

   public class ContactDetail

   {

       [StringLength(100)]

       [DisplayName("Contact Name")]

       [DisplayFormat(NullDisplayText = "")]        

       public virtual string Contact { get; set; }

       [Email]

       [StringLength(100)]        

       [DisplayName("Email")]

       public virtual string Email { get; set; }

       public virtual PhoneInfo phoneInfo { get; set; }

   }

But I don't know what to do next and how to introduce these two new classes into my Client class to correctly associate column names. Also, in this case the complex type will be nested (PhoneInfo is already a complex type and it's part of the complex type ContactDetail).

Do you see how should I modify my Client class?

Thanks a lot in advance.

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

Friday, October 19, 2012 4:11 PM by Naom

I found some code in your earlier reply to someone's comment -

public class EntityMappingContext : DbContext

{

   public DbSet<User> Users { get; set; }

   protected override void OnModelCreating(ModelBuilder modelBuilder)

   {

       modelBuilder.Configurations.Add(new UserConfiguration());

   }

}

class UserConfiguration : EntityTypeConfiguration<User>

{

   public UserConfiguration()

   {

       Property(u => u.DeliveryAddress.Street).HasColumnName("DeliveryAddress_Street");

       Property(u => u.DeliveryAddress.City).HasColumnName("DeliveryAddress_City");

       Property(u => u.DeliveryAddress.PostalCode).HasColumnName("DeliveryAddress_PostalCode");

       Property(u => u.HomeAddress.Street).HasColumnName("HomeAddress_Street");

       Property(u => u.HomeAddress.City).HasColumnName("HomeAddress_City");

       Property(u => u.HomeAddress.PostalCode).HasColumnName("HomeAddress_PostalCode");

   }

}

So, I suspect it may work for my scenario - right? (Contact1 and Contact2 both having another complex type of Phone)

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

Friday, October 19, 2012 5:32 PM by Naom

I ran into a bug, please see the whole description here

social.msdn.microsoft.com/.../6a9cc309-5767-4db4-a039-fb7f17d13821

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

Friday, January 18, 2013 2:51 AM by ElmarG

Any ideas for moving complex types inside a base class and using TPC strategy?. Eg.

public class Audit

   {

      public string By {get; set;}

      public DateTime At {get; set;}

   }

   public abstract class EntityBase

   {

      protected EntityBase()

      {

         Created = new Audit();

      }

      public int Id {get; set;}

      public Audit Created { get; private set;}

   }

   public class Product : EntityBase

   {

     public string Name { get; set; }

   }

   public class MyDataContext : DbContext

   {

       public MyDataContext()

           :base("database-connection-key")

       {

       }

       public DbSet<Product> Products { get; set; }

   }

Any ideas what configuration would be needed to end up with a 'Product' table consisting of the following columns: Id, Created_By, Created_At, Name?