Friday, March 14, 2008

I just finished full support for using complex types in EFContrib. I thought I'd quickly share what complex types are and how they are used in Entity Framework.

Julie Lerman blogged about Complex Types here, where she also shows how to use them. Check her post for a great example.
In Daniel Simmons' words:
Complex types “Complex types” is the Entity Framework name for value properties which have more intricate structure than scalars. The canonical example is an Address type which contains several parts (street, city, state, etc.) Complex types are somewhat like entities except that they do not have any identity of their own (they are value types). This means that a complex type instance is always a part of some other enclosing entity—it can’t stand on its own, it doesn’t have relationships, etc. In this release, the mapping scenarios for complex types are significantly limited: inheritance is not supported, complex type properties cannot be null and they can only occur in single instances, not collections.

So, a complex type can be seen as a struct, without identity.
Let's create a complex type. I will have a person table with 3 address related columns. My person object though, should have a property named 'Address' which points to a class of type Address.
The CSDL looks like this:

        <EntityType Name="Person">
          <Key>
            <PropertyRef Name="PersonID" />
          </Key>
          <Property Name="PersonID" Type="Int32" Nullable="false" />
          <Property Name="FirstName" Type="String" Nullable="false" MaxLength="50" Unicode="false" />
          <Property Name="LastName" Type="String" Nullable="false" MaxLength="50" Unicode="false" />
          <Property Name="Address" Type="Self.Address" Nullable="false" />
        </EntityType>
        <ComplexType Name="Address">
          <Property Name="City" Type="String" Nullable="false" MaxLength="50" Unicode="false" />
          <Property Name="Street" Type="String" Nullable="false" MaxLength="50" Unicode="false" />
          <Property Name="PostalCode" Type="String" Nullable="false" MaxLength="10" Unicode="false" />
</ComplexType>

Pretty clear: our Person has an address property, with a type of 'Self.Address'. Make sure it is not Nullable. The Address is defined just like you would expect. Please know that the current designer does not allow designing complextypes visually, which is why I did it in xml.

The database looks like this:

        <EntityContainer Name="dbo">
          <EntitySet Name="Person" EntityType="ComplexTypesTestModel.Store.Person" />
        </EntityContainer>
        <EntityType Name="Person">
          <Key>
            <PropertyRef Name="PersonID" />
          </Key>
          <Property Name="PersonID" Type="int" Nullable="false"  StoreGeneratedPattern="Identity" />
          <Property Name="FirstName" Type="varchar" Nullable="false" MaxLength="50" />
          <Property Name="LastName" Type="varchar" Nullable="false" MaxLength="50" />
          <Property Name="Street" Type="varchar" Nullable="false" MaxLength="50" />
          <Property Name="City" Type="varchar" Nullable="false" MaxLength="50" />
          <Property Name="PostalCode" Type="varchar" Nullable="false" MaxLength="10" />
</EntityType>

Here we see a row with all columns in it. Darned DBA's!!

To map that database description to the classes, we take a look at the C-S mapping:

          <EntitySetMapping Name="Person">
            <EntityTypeMapping TypeName="IsTypeOf(EntityFrameworkContrib.PostSharp4EF.Testing.ComplexType.Person)">
              <MappingFragment StoreEntitySet="Person">
                <ScalarProperty Name="PersonID" ColumnName="PersonID" />
                <ScalarProperty Name="FirstName" ColumnName="FirstName" />
                <ScalarProperty Name="LastName" ColumnName="LastName" />
                <ComplexProperty Name="Address">
                  <ScalarProperty Name="City" ColumnName="City"/>
                  <ScalarProperty Name="Street" ColumnName="Street"/>
                  <ScalarProperty Name="PostalCode" ColumnName="PostalCode"/>
                </ComplexProperty>
              </MappingFragment>
            </EntityTypeMapping>
</EntitySetMapping>

As you can see, the complexproperty is defined within the Person mapping. That caught me off-guard for a while.

EFContrib support

I have not checked in the source yet, but I will shortly at http://www.codeplex.com/efcontrib.
As you know, my contribution project to Entity Framework aims to help you use Entity Framework without all the generated code. You can just create your own domain model and add one attribute. The system will actually change the code to facilitate the EDM during compilation. Leaving you with a clean model.

It was actually quite difficult to implement this behind the scenes. To support normal entitytypes, I have to implement the three IPoco interfaces. But complex types are radically different. In the end, I had to alter the code I put into the setters of your properties.
I also had to somehow get hold of a list of properties in your type that are complexTypes (in this case Address). When the system injects your entitytype with a changetracker, it should notify all complex types. I could have done that with reflection, but we all know that's really slow. So I actually generate a method in your entity: 'UpdateComplexTypes(tracker)' and insert that with the correct IL to set the tracker in all the complextype-properties. So the solution is as fast as it can get, completely on par with handwritten c#. I may have to write another post on how I did it.

Our domain objects look like this:

  0 [Poco("ComplexTypesTestEntities")]
  1  public class Person
  2 {
  3   public int PersonID { get; set; }
  4   public string FirstName { get; set; }
  5   public string LastName { get; set; }
  6   public Address Address { get; set; }
  7 }
  8
  9 [Poco("ComplexTypesTestEntities")]
  10  public class Address
  11 {
  12   public string City { get; set; }
  13   public string Street { get; set; }
  14   public string PostalCode { get; set; }
  15 }
  16

Now, this code will work great:

  0    using (ComplexTypesTestEntities context = new ComplexTypesTestEntities())
  1    {
  2     // clear out database
  3     foreach (Person old in context.Person)
  4     {
  5      context.DeleteObject(old);
  6     }
  7     context.SaveChanges();
  8
  9     Person p = new Person { FirstName = "Ruurd", LastName = "Boeke" };
  10
  11     // this will set the changetracker
  12     context.AddToPerson(p);
  13
  14     Address a = new Address { City = "Rotterdam", Street = "My Street", PostalCode = "1111 VA" };
  15     p.Address = a;
  16
  17     IGetChangeTracker ctA = PostSharp.Post.Cast<Address, IGetChangeTracker>(a);
  18     Debug.Assert(ctA.GetChangeTracker() != null);
  19
  20     Address b = new Address { City = "Seattle", Street = "redmond street", PostalCode = "2222 BB" };
  21     p.Address = b;
  22     Debug.Assert(ctA.GetChangeTracker() == null);
  23
  24     IGetChangeTracker ctB = PostSharp.Post.Cast<Address, IGetChangeTracker>(b);
  25     Debug.Assert(ctB.GetChangeTracker() != null);
  26
  27     context.SaveChanges();
  28    }

You can see me casting the object to the interface I implemented on lines 17 and 24.

Friday, October 15, 2010 12:28:09 PM (Romance Standard Time, UTC+01:00)
That is the type we have adorned with our attribute (your 'Person' Poco class, for instance). Then, I specify that I want 3 other aspects to work on this type!
Tuesday, October 26, 2010 2:46:52 AM (Romance Standard Time, UTC+01:00)
href="http://www.feetlockers.com/reebok-easytone-c-25.html">Reebok ZigTech</a> tests the shoes on real runners who fill in a detailed questionnaire at the start, mid-way and end of 300-mile increments. They’re light, flexible and so comfortable. <a href="http://www.feetlockers.com/reebok-easytone-c-25.html">Reebok ZigTech shoes</a> footwear, training longer just got easier.<a href="http://www.feetlockers.com/reebok-easytone-reebok-easytone-womens-shoes-c-25_28.html">Reebok Easytone Shoes</a> has the top technology which uses shoes’ energy and transfers it horizontally. ZigTech helps to transfer weight through the whole range of motion by pushing the force of the strike through to the front of your foot. <a href="http://www.feetlockers.com/specials.html">Discount Reebok zigtech</a> footwear is designed to protect your feet and return energy to the athlete for a soft and springy ride. The foam is lightweight. Forefoot flex grooves for added <a href="http://www.feetlockers.com/reebok-easytone-reebok-zig-pulse-running-shoes-c-25_26.html">Reebok EasyTone</a> flexibility. This ultimately enables athletes to stay healthier during in this season.<br>
Tuesday, October 26, 2010 2:47:11 AM (Romance Standard Time, UTC+01:00)
href="http://www.zigtechshoesonsale.com/mbt-men-shoes-mbt-sandals-shoes-c-8_11.html"><strong>Cheap mbt shoes</strong></a> is not too high, if the heel is higher than 3.5 cm, it will increase the risk of lumbar lordosis and lumbosacral angle, which easily lead to fatigue and lower back pain and lumbosacral joint.Moreover, the girls who wear high heels early will lead to <a href="http://www.zigtechshoesonsale.com/mbt-men-shoes-mbt-casual-shoes-c-8_9.html"><strong>Discount Mbt Shoes</strong></a> the developing pelvic tilt, which make the <a href="http://www.zigtechshoesonsale.com/mbt-men-shoes-mbt-sandals-shoes-c-8_11.html"><strong>Mbt shoes clearance</strong></a>, is demanding.However, they are not only for people on their feet but for anyone who wants to wear a pair of comfortable <a href="http://www.zigtechshoesonsale.com/mbt-women-shoes-mbt-sports-shoes-c-15_26.html"><strong>Mbt shoes outlet</strong></a> that takes the pain away from your body when you are standing and walking. That’s why you need to wear <a href="http://www.zigtechshoesonsale.com/mbt-men-shoes-mbt-casual-shoes-c-8_9.html"><strong>MBT Sandals Shoes</strong></a>.
Thursday, November 04, 2010 4:40:36 AM (Romance Standard Time, UTC+01:00)
http://www.coachusabags.com/
http://www.asics-us.com/
http://www.ukuggus.com/
http://www.mbt-usa.com/
Thursday, November 25, 2010 12:44:22 PM (Romance Standard Time, UTC+01:00)
That is the type we have adorned with our attribute (your 'Person' Poco class, for instance). Then, I specify that I want 3 other aspects to work on this type!
Thursday, December 02, 2010 3:42:02 AM (Romance Standard Time, UTC+01:00)
This article was Very helpful. Actually, I am fond of reading online punjabi news. Thanks for writing such a complete ..
thank you for sharing.
Thursday, December 02, 2010 8:25:23 AM (Romance Standard Time, UTC+01:00)
xiaolaba Only after before a "concept, unlike other principles vile ugg boots on sale and difficult to understand, on the contrary boots uggs on sale, it is simple and easily arouses the child's confidence and high spirits, goals are small but specific ugg boot sale. In this goal, the child without understanding thoughts, solid, conscientious to do with bailey button, abandoned children in a meeting in surface. Small success to classic mini uggs, and gets the others recognized and appreciated, will gradually moving towards greater success mini uggs on sale, you'll make a big career. Words can ruin a man's confidence uggs mini on sale, even burst of his hopes of survival classic mini uggs on sale, But a word can also encourage one from loss to come out, or make one from a new Angle know yourself ugg classic cardy, changed his life. So at any time, we don't save said an encouraging word, give a trusting eyes ugg classic short, do a duck-yard trifle. A person's strength for himself perhaps is very limited ugg classic short navy, but he has probably help stimulate another person's infinite potential ugg boot sale.
Comments are closed.