Monday, 18 February 2008

In this post I'd like to introduce version 0.1 of the first Entity Framework contribution project: Automatically implement the IPoco interfaces.
The project is aimed at helping you build your domain layer in a more persistence ignorant way, than is possible at this moment.

[official codeplex location of the project is here]

The full table of contents:

The Problem: baseclass needed

Microsoft is on the brink of releasing the Entity Framework. It is at beta 3 at this moment. If you are reading this blog, you are probably familiar with it, but let's do a quick summary:
The Entity Framework is a framework that maps between a database and your domain objects. It's grand vision is to easily allow you to (with a funky design-experience) create (multiple) conceptual models that know how to talk to the database. Although more than an OR-mapper, most people like to position it as such anyway.
EF is an abstraction layer on top of your datastore and will allow you to work with business objects that actually make sense from an object-oriented perspective, instead of making you work with datarows, tables and sets.

One part of the criticism that the Entity Framework gets at this moment, is the lack of persistence ignorance. This means that, when you use the Entity Framework, you will have to create business entities that are aware of the Entity Framework (they need to derive from a Entity Framework baseclass).
This goes against too many principles to mention, and the ADO.Net team have gotten quite a bit of comments about it (other more mature frameworks, like nHibernate do not force you into this). Rightfully so!
In the end, Daniel Simmons blogged about the criticism here: Persistence Ignorance: OK, I think I get it now.

The suggested Solution: implement interfaces

In order to take away the need to implement a base-class, the EF-team created a few interfaces that need to be implemented. That is as far as they can go in the first release.

So, you can implement 3 interfaces on your business objects, and no baseclass is needed. 
Although much better, I feel I should not have to spend time on, or burden my domain layer with, code to facilitate data access. My domain layer should be able to focus on one thing: solving the business problems of the client.
By introducing other code to my domain layer, developers will be distracted.

Bill McCafferty posts about DDD (Domain Driven Design) and EF here. He concludes:

In short, and at the risk of being laconic, I feel that the ADO.NET Entity Framework does for data communications what the ASP.NET page life cycle did for the presentation layer.  In trying to introduce simplification and increased productivity, it's actually going to result in higher complexity and decreased maintainability in the long run.  I appreciate what Microsoft is trying to do, and absolutely love some of their other ideas, but, for now, I'm going to pass on the ADO.NET Entity Framework.

Billy McCafferty

He is quite right!!

EF-Contrib: Easing the implementation of these interfaces

The 3 interfaces we are talking about are:

  • IEntityWithChangeTracker
  • IEntityWithKey
  • IEntityWithRelationships

Implementing these interfaces is sometimes called "IPoco": Poco stands for Plain Old C# (or Code) Object, and the I in IPoco means that you can still use your Poco object but have to implement these interfaces. (so, not Poco at all... but still!)

The current checked in project (find it here) uses Postsharp to actually change the IL-code of your assembly and implements these interfaces. That means that you can build a domain layer with a class like this:

    [Poco("ConnectionName")]
    public class Person
    {
        public int PersonID { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
    }

After compilation, the class will actually look a bit different on disk:

    public class Person : IEntityWithChangeTracker, IEntityWithKey, IEntityWithRelationships
    {
...
    }

So you can use this Person class, like you would use the classes that EF generates.

It is important to understand that there will be very little runtime performance costs involved. The code transformation is done at compile-time, once. At runtime, there is no magic AOP or whatever involved.

This approach is used by several other OR-Mappers and is very common in the Java world.

Is this Persistence Ignorance?

Obviously, it's not. Hopefully, in version 2.0 of the Entity Framework, full ignorance is achieved. However, if you want to use EF at your datalayer today, this approach will let you focus on the important stuff, instead of data access code.

Imagine changing your conceptual model. When implementing IPoco yourself, you will have to take care to change all kinds of attributes on top of your properties. This will quickly become a burden.

How does it work?
  • You will need to download and install Postsharp on all the machines that will build your application (developer machines and teambuild machine(s)).
  • Your domain layer will have to reference the EntityFrameworkContrib.PostSharp4EF assembly, and the PostSharp.Laos and PostSharp.Public assemblies. By referencing these, Postsharp will know to do a post-compilation phase on your assemblies.
  • You will need to supply a 'psproj' file in your assembly, to let our attribute know where it should look to actually do the implementation. This allows me to seperate the implementation assembly from what you need at runtime!
  • You have already created your edmx file, which EF will dissect into the individual .csdl, .msl and .ssdl files and place them in your bin/debug folder.
  • The project for now assumes a connection string to be present in your app.config
  • You can create your own simple business object.
  • That connection string is needed during the postcompilation phase to get to the individual mapping files, so use the attribute [Poco("")] to let us know you need to change this class.
  • The interfaces are implemented and the setters of your properties are modified to actually do changetracking
  • Actually, at this moment: INotifyPropertyChanged is implemented as well (let me know if you actually want this).

So, let's first look at the psproj file you need. In the Test-project, there is one already:

<Project xmlns="http://schemas.postsharp.org/1.0/configuration">
	<SearchPath Directory="../EntityFrameworkContrib.PostSharp4EF.Weaver/bin/{$Configuration}"/>
	<SearchPath Directory="{$SearchPath}" />
	<Tasks>
		<AutoDetect />
		<Compile TargetFile="{$Output}" IntermediateDirectory="{$IntermediateDirectory}"  CleanIntermediate="false" />
	</Tasks>
</Project>

The referenced assembly EntityFrameworkContrib.PostSharp4EF only defines the Poco attribute, but does not contain the actually 'code-weaving'. If we would have placed the code-weaving in the same assembly as the Poco-attribute, you would have a much larger assembly to reference and you could get into licensing problems. By separating them, you only need to reference a tiny assembly.

The weaving assembly should not be distributed with your final product!

However, during the build, PostSharp does need to find the weaving assembly. Therefor, you need to create a psproj file that extends it's normal searchpath to also include the weaving dll.
Take care in naming the file: it should be named "projectname.psproj".

When the project is more mature, you might find it best to actually just place the weaving assembly into one of the default searchpaths for postsharp to find, and you will not need this psproj file.

Now, let's look at our attribute:
In it's constructor, it takes the name of the EDMcontainer, which should match your connection string. I have also added a few properties: Name, NamespaceName, PathToConfigFile. I'll get back to these in a later post. In the future, others will be added.

During the weaving, I have to do quite a bit of work to actually get to the correct mapping files. So, I try to load in your app.config and extract the file path's from it. The Testproject has the following app.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="OneSimpleTypeConnection" connectionString="metadata=.\bin\debug\OneSimpleType\OneSimpleType.csdl|.\bin\debug\OneSimpleType\OneSimpleType.ssdl|.\bin\debug\OneSimpleType\OneSimpleType.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=VISTAX64\SQLEXPRESS;Initial Catalog=EntityFrameworkTest;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

So, after loading that app.config, I use the supplied ConnectionContainer to get that connectionstring, and then use some simple regex work to get the path's to the mapping files. Then I try to load these to create a MetadataWorkspace.

When I finally have a MetadataWorkspace, stuff get's easier: I can iterate the properties in our original class and find the property in the metadataworkspace. Then I create the correct EDMScalar Attributes on top of those.

Implementing the interfaces is done by PostSharp, where it will look at an interface and just use a class I provide to call when one of the interface methods is called.

The result

Let's look through reflector at how the end result looks like. I won't show the methods, to keep things short and sweet.

  1 [EdmEntityType(Name="Person", NamespaceName="EntityFrameworkContrib.PostSharp4EF.Tests.OneSimpleType")]
  2 public class Person : INotifyPropertyChanged, IComposed<INotifyPropertyChanged>, IProtectedInterface<IFirePropertyChanged>, IPocoFacade, IComposed<IPocoFacade>
  3 {
  4     // Fields
  5     private IPocoFacade ~EntityFrameworkContrib.PostSharp4EF.IPocoFacade;
  6     private readonly InstanceCredentials ~instanceCredentials;
  7     private INotifyPropertyChanged ~System.ComponentModel.INotifyPropertyChanged;
  8     [CompilerGenerated]
  9     private string <Firstname>k__BackingField;
10     [CompilerGenerated]
11     private string <Lastname>k__BackingField;
12     [CompilerGenerated]
13     private int <PersonID>k__BackingField;
14
15     // Methods
16     static Person();
17     public Person();
18     void INotifyPropertyChanged.add_PropertyChanged(PropertyChangedEventHandler value);
19     EntityKey IEntityWithKey.get_EntityKey();
20     RelationshipManager IEntityWithRelationships.get_RelationshipManager();
21     void INotifyPropertyChanged.remove_PropertyChanged(PropertyChangedEventHandler value);
22     void IEntityWithKey.set_EntityKey(EntityKey value);
23     void IEntityWithChangeTracker.SetChangeTracker(IEntityChangeTracker changeTracker);
24     protected InstanceCredentials GetInstanceCredentials();
25     [DebuggerNonUserCode]
26     IPocoFacade IComposed<IPocoFacade>.GetImplementation(InstanceCredentials credentials);
27     [DebuggerNonUserCode]
28     INotifyPropertyChanged IComposed<INotifyPropertyChanged>.GetImplementation(InstanceCredentials credentials);
29     [DebuggerNonUserCode]
30     IFirePropertyChanged IProtectedInterface<IFirePropertyChanged>.GetInterface(InstanceCredentials credentials);
31
32     // Properties
33     [EdmScalarProperty(IsNullable=true)]
34     public string Firstname { [CompilerGenerated] get; [CompilerGenerated] set; }
35     [EdmScalarProperty(IsNullable=false)]
36     public string Lastname { [CompilerGenerated] get; [CompilerGenerated] set; }
37     [EdmScalarProperty(IsNullable=false, EntityKeyProperty=true)]
38     public int PersonID { [CompilerGenerated] get; [CompilerGenerated] set; }
39 }
40
41

Line 1 implements the needed EntityType attribute for EDM to work.
Line 2 shows that INotifyPropertyChanged and IPocoFacade is implemented. The facade interface just hides the 3 IPoco interfaces, so that's them! PostSharps adds IComposed interfaces as well.
Line 26 shows a call to the GetImplementation method of that interface. This way, a class I have added is returned where the actual work of the interface is done.
Line 33, 35 and 38 show the EDMScalarProperties being set.

What it does not do at this moment

I do not set default values for fields and I haven't spend any time on complex types and relations.

I first want to gauge community interest before spending more time on this project. So let me know if you would use this approach if it would be complete. I'm quite sure these things aren't too hard to accomplish, but they will take some time.

The Future

I'd like the EntityFramework Contrib project to provide easy tools to use EF in an enterprise system. I'm mostly interested in client/server SOA solutions. Other projects that might help in that aspect:

  • A custom changetracker that can be used on the client. This way the client will not have to reference Entity Framework at all.
  • Better serialization possibilities. Note that I do not automatically place datacontract attributes on top of the properties. I think it was a mistake for the ADO.Net team to implement their codegen to do this. (although I understand why).
    When I serialize a EF entity at this moment, I see all kinds of references to EF in the xml. I do not like that, and would like a beautiful clean xml representation of my business objects. (I don't want to be forced to use DTO's.).
  • Serializing original values. I can see a representation of the value with a xml attribute that shows what the original value was.

 

Feel free to contact me, or leave a comment here or at the projects home to let me know if you are interested!

kick it on DotNetKicks.com

Monday, 18 February 2008 14:50:21 (Romance Standard Time, UTC+01:00)  #    Comments [46]  |  Trackback
 Saturday, 05 January 2008

Let's mix things up!
One of the strengths of the Entity Framework is it's mapping mechanism, which uses views to represent the data needed for an entity. As they call it 'some clever magic' allows the EF to fold and unfold data into views, solving the problem that most database systems (including oracle) do not solve for you: updating and inserting into a view that consists of more than 2 tables.
This allows us to map more information when needed.

In our previous examples, an employee table was defined in the database and our conceptual model used the Table Per Hierarchy mapping strategy to map developers, testers and business analists to that table. We now find that we have quite a bit of information that we need to store about the developers (such as their skill-set) that is of no use to the other types of employees. We could very well add a bunch of nullable columns to the employee table. However, one can only sustain that much filth for a certain time period ;-) Going down that path will soon get out of hand. It's better to create a new table that will hold the information we seek. (Or would you rather create a universal table???)

Thus a new table 'DevelopmentSkills' is added and a primary key DeveloperID is created, along with a few boolean columns. A foreign key relation is created between the Employee table and the new table. Nothing fancy:

EF_Combining_DBDiagram.jpg

I've learned by now that it's best to create the SSDL by hand. So I add the new table to the SSDL:

        <EntityType Name="DevelopmentSkills">
          <Key>
            <PropertyRef Name="DeveloperID" />
          </Key>
          <Property Name="DeveloperID" Type="int" Nullable="false" />
          <Property Name="WPF" Type="bit" Nullable="false" Default="false" />
          <Property Name="WCF" Type="bit" Nullable="false" Default="false" />
          <Property Name="WF" Type="bit" Nullable="false" Default="false" />
          <Property Name="EF" Type="bit" Nullable="false" Default="false" />
        </EntityType>
And the more important association:
        <Association Name="FK_DevelopmentSkills_Employee">
          <End Role="Employee" Type="EntityFrameworkTestModel1.Store.Employee" Multiplicity="1" />
          <End Role="DevelopmentSkills" Type="EntityFrameworkTestModel1.Store.DevelopmentSkills" Multiplicity="0..1" />
          <ReferentialConstraint>
            <Principal Role="Employee">
              <PropertyRef Name="EmployeeID" />
            </Principal>
            <Dependent Role="DevelopmentSkills">
              <PropertyRef Name="DeveloperID" />
            </Dependent>
          </ReferentialConstraint>
        </Association>

This association represents the foreignkey in the database and should be pretty clear by now.
Don't forget to define the sets in the entitycontainer.

Then I was able to use the designer to first create extra properties in the 'einstein' class, our junior developer ;-)
In the mapping designer, choose to map to DevelopmentSkills. Set the DeveloperID column to the PersonID property and map the remaining properties.

Pretty neat, we did not have to map another class, but instead, just extended our current class.

That means that this code is now possible:

Einstein smartNerd = new Einstein()
{
Firstname = "Albert",
Lastname = "Einstein",
Language = "C# 3.5",
WCF = true, WPF = true, WF = true, EF = true,
TeamLeader = e,
};
context.AddToPerson(smartNerd);

Elvis elvis = new Elvis()
{
Firstname = "Elvis",
Lastname = "Presley",
Language = "C# 2.0",
WPF = true, EF = true,
TeamLeader = e,
};
context.AddToPerson(elvis);

One thing to note though: the current designer makes a mistake when mapping the extra table to the Einstein class. It keeps adding new entitytypemappings in the CSDL, with the new mapping fragment (to developmentskills table) instead of combining the fragments in the already defined entitytypemapping. This leads to an error keeping the designer from showing any info. I had to hand edit a few times ;-(

 

 

Saturday, 05 January 2008 23:15:36 (Romance Standard Time, UTC+01:00)  #    Comments [2]  |  Trackback

We have seen two types of inheritance modeling, at this point I'm interested in modeling an association. This actually turned out to be harder then I had expected, even though the documentation on this subject is good and plentyfull ;-)

However, since you are still reading, I will create a very simple example in the employee class, such that an employee needs to report to another employee.
Remember that employee inherits from person. I was happy to see that I was indeed able to create the relationship!

I've added a new column in the employee table, named: ReportsToID and a foreignkey relation that specifies the primary key base to be Employee/EmployeeID and the foreign key base to be Employee/ReportsToID. In database lingo this simple means that ReportsToID can be filled with an exact EmployeeID and that this relationship is verified (for instance, when deleting an employee, but still having other employees which report to the deleted employee).

 Let's look at the SSDL that I created to match this new foreignkey relationship:

In the EntityContainer section:
          <AssociationSet Name="FK_Employee_Manager"
                          Association="EntityFrameworkTestModel1.Store.FK_Employee_Manager">
            <End Role="Manager" EntitySet="Employee" />
            <End Role="Members" EntitySet="Employee" />
          </AssociationSet>
And the mentioned AssociationSet:
        <Association Name="FK_Employee_Manager">
          <End Role="Manager" Type="EntityFrameworkTestModel1.Store.Employee" Multiplicity="0..1" />
          <End Role="Members" Type="EntityFrameworkTestModel1.Store.Employee" Multiplicity="*" />
          <ReferentialConstraint>
            <Principal Role="Manager">
              <PropertyRef Name="EmployeeID" />
            </Principal>
            <Dependent Role="Members">
              <PropertyRef Name="ReportsToID" />
            </Dependent>
          </ReferentialConstraint>
        </Association>

As you can see, I named the roles: Manager and Members.
The association can be interpreted as follows: An employee (a Member) can have zero or one Manager. A Manager can have zero to infinite Members.

Let's take a look at the C-side of life.
In the EntityContainerSection:
          <AssociationSet Name="TeamMemberToTeamLeader"
                          Association="EntityFrameworkTestModel1.TeamMemberToTeamLeader">
            <End Role="TeamMembers" EntitySet="Person" />
            <End Role="TeamLeader" EntitySet="Person" />
          </AssociationSet>
And the Association is defined as:
        <Association Name="TeamMemberToTeamLeader">
          <End Type="EntityFrameworkTestModel1.Employee" Role="TeamLeader" Multiplicity="0..1" />
          <End Type="EntityFrameworkTestModel1.Employee" Role="TeamMembers" Multiplicity="*" />
        </Association>

I like to use real desciptive names, but this should be easy enough to follow.

Also, I added navigationProperties to my model, so I can easily follow an association:
        <EntityType Name="Employee" BaseType="EntityFrameworkTestModel1.Person">
          <NavigationProperty Name="TeamLeader" Relationship="EntityFrameworkTestModel1.TeamMemberToTeamLeader" FromRole="TeamMembers" ToRole="TeamLeader" />
          <NavigationProperty Name="TeamMembers" Relationship="EntityFrameworkTestModel1.TeamMemberToTeamLeader" FromRole="TeamLeader" ToRole="TeamMembers" />
        </EntityType>

Remember that an association is an independent entity, it only defines a relation that can be traversed. We need Navigationproperties to actually use the association. This way it can be shared between models.

The actual mapping between the store and the conceptual model is interesting:
          <AssociationSetMapping Name="TeamMemberToTeamLeader"
                                 TypeName="EntityFrameworkTestModel1.TeamMemberToTeamLeader"
                                 StoreEntitySet="Employee" >
            <EndProperty Name="TeamMembers">
              <ScalarProperty Name="PersonID" ColumnName="EmployeeID" />
            </EndProperty>
            <EndProperty Name="TeamLeader">
              <ScalarProperty Name="PersonID" ColumnName="ReportsToID" />
            </EndProperty>
            <Condition ColumnName="ReportsToID" IsNull="false" />
          </AssociationSetMapping>

Here you can see that I am mapping the ScalarProperty PersonID instead of EmployeeID; remember we are using inheritance here.

The condition is needed to solve some errors I was having. I think it can be read as: the association only works if there is a reportsID value set.

Some test code:

Employee e = new Employee();
e.Firstname = "Ian";
e.Lastname = "Mort";
context.AddToPerson(e);

Einstein smartNerd = new Einstein();
smartNerd.Firstname = "Albert";
smartNerd.Lastname = "Einstein";
smartNerd.Language = "C# 3.5";
smartNerd.TeamLeader = e;
context.AddToPerson(smartNerd);

Elvis elvis = new Elvis();
elvis.Firstname = "Elvis";
elvis.Lastname = "Presley";
elvis.Language = "C# 2.0";
elvis.TeamLeader = e;
context.AddToPerson(elvis);

At this point I can check that e.TeamMembers has a count of 2 and both employees have a teammember property! So, everything working as expected.

Reading back this post, I can see it was actually pretty simple. However, the syntax seems to be overly complex and a small mistake leads to weird errors!

 

Saturday, 05 January 2008 15:09:31 (Romance Standard Time, UTC+01:00)  #    Comments [1]  |  Trackback
 Friday, 04 January 2008

Last post showed a very simple database setup with a Person, a Customer and an Employee-table. They were mapped to different classes in what is called a Table per Type mapping.

A different kind of mapping strategy is the Table Per Hierarchy mapping, where all the types in your hierarchy are mapped to the same table. In many cases your dba will not understand why there should be different tables for information that can clearly be represented within the same table! For instance, different types of employees (developer, manager, architects) will certainly re-use the employee table, where very often a column is added to differentiate between these types.

Far be it from me to disagree with such a database-schema. It makes perfect sense and is a clear example of the Object relational impedance mismatch. The domain-model needs to break free of these kinds of reasoning and needs to define it's own hierarchy.
It can do so by leveraging the column that was added to diffentiate between types. In OR-Mapping, it is called a discriminator column, as the system can use it to discriminate between different the class-type it should use.

I added a number of fun classes to the model, that represent developers: Einstein, Elvis and Mort. In this company, each inherits properties from the other, in a possibly unexpected way ;-)
There is also the Business analist and a Tester.

All these types have properties that are mapped to the same table. However, as your dba has come to understand, the different types of employees do differ a little and in time this has led to the introduction of a few extra columns in the employee table: 'ProgrammingLanguage' and 'TestMethodology'. Too bad these have to be nullable, because they don't make sense in all cases!
Also, the functionname column of the previous post was changed to functiontype (int) and will act as the discriminator.

Our database now looks like this:

EF_TPH_DBDiagram..jpg

Nothing fancy here.

To create the conceptual model, I could use the designer. Again, if I update from the database, the model becomes useless, but editing the SSDL was easy enough in this case.
Adding the new entities in the model designer was also easy:

  • There should not be a scalar property 'FunctionType' in the model. The discriminator works behind the scenes, and that is a good thing! As a user of the domain model, you should not need to know about it.
  • Only when you delete that property, can it be used as a 'condition', which basically is the condition that EF uses to see which class-type it should instantiate.
  • To map the condition, you need to map the various types to the employee table, even though they are already mapped through their parent 'Employee'!! No properties need to be mapped though.
  • When adding the condition, a value can be set. When you set the value, the designer does make an error in the xml which you will have to fix yourself!! So, when I wanted the type 'Einstein' to have the condition 'FunctionType = 1', I let the designer create it, and went to the line the build error indicates as being wrong. There I changed some weird value like '_x3301' to just '1'.

The model now looks like this:

EF_TPH_ConceptualModel..jpg

Using the following test code:

....

Einstein smartNerd = new Einstein();
smartNerd.Firstname = "Albert";
smartNerd.Lastname = "Einstein";
smartNerd.Language = "C# 3.5";
context.AddToPerson(smartNerd);

Elvis elvis = new Elvis();
elvis.Firstname = "Elvis";
elvis.Lastname = "Presley";
elvis.Language = "C# 2.0";
context.AddToPerson(elvis);

Mort mort = new Mort();
mort.Firstname = "Mort";
mort.Lastname = "Builder";
mort.Language = "VB.Net";
context.AddToPerson(mort);

BusinessAnalist George = new BusinessAnalist();
George.Firstname = "George";
George.Lastname = "Clooney";
context.AddToPerson(George);

Tester tester = new Tester();
tester.Firstname = "UnitTests";
tester.Lastname = "Rock";
tester.Methodology = "TMap";
context.AddToPerson(tester);

....

I got the following expected outcome:

Ian, Mort is a Employee
Albert, Einstein is a Einstein
Ruurd, Boeke is a Person
Silvia, Banana is a Customer
George, Clooney is a BusinessAnalist
UnitTests, Rock is a Tester
Elvis, Presley is a Elvis
Mort, Builder is a Mort

The employee table was filled like this:

55 0 NULL NULL
56 1 C# 3.5 NULL
59 4 NULL NULL
60 5 NULL TMap
61 2 C# 2.0 NULL
62 3 VB.Net NULL

So, that's all there is to it.
Hopefully the data-team will fix the mapping bug in the next ctp!

Next up, I will mix it up just a bit.

Friday, 04 January 2008 01:17:45 (Romance Standard Time, UTC+01:00)  #    Comments [7]  |  Trackback
 Wednesday, 02 January 2008

I'm going to jump right into the Entity Framework here, with a simple how-to. If you want a gentle introduction into this technology, you can probably read some future posts, but you will be far better off reading the ADO.Net teamblog or better still, read all of the entries of Danny Simmons.

An OR-mapper needs to be flexible in mapping your domain classes, so you can describe your domain as truthfully as possible. The entity framework positions itself to be more than an OR-Mapper: it sees itself as a translation technology between models. One of those models is defined by your database, the other by your domain (your conceptual model). It's interesting to see what types of inheritance are possible. In this post I will give a sample of the Table Per Type (TPT) inheritance, where you define an inheritance in your conceptual model and use different tables to persist the data.

The way to implement this is fairly straightforward and documented, however, I certainly had some problems getting it to work. As did Scott Allen, so I thought I would create a small walk through for this scenario.

EF_TBT_DBDiagram.jpg

As you can see, my database (SqlExpress) has 3 tables. The 'Person' table, a customer table and an employee table. There are foreign key relations between them, with the Person table being the Primary/Unique Key Base Table and the Customer and Employee tables being the Foreign Key Base Tables. It is important to note that the PersonID column is set up to automatically generate ID's, and the CustomerID and EmployeeID columns are not: we want to create a situation where an object like Customer is persisted to these two tables (customer and person) and the Person table is the one supplying a new ID. The Customer table will just use that PersonID as it's own CustomerID.

That concludes the database schema, next up is the conceptual model, ugh, I mean domain model:

EF_TBT_ConceptualModel.jpg

This is how I want to my conceptual model to look like.  

When you have just generated the model from the database, the foreign key relations are visible. Remove them! Then, also remove the CustomerID and EmployeeID properties that were generated. Add the two inheritance links.
Since Customer already maps to Person (through the inheritance) you do not have to map these again. You do have to add a mapping to the customer table. The key point here is that the CustomerID column needs to be mapped to the PersonID property. Same goes for Employee.

Now, this is all there is to it. Before we dive into the XML generated, let me just point this out: when you update from the database again, the designer will fail. This is a major problem, where the synchronization just isn't good enough. It will encounter problems with the foreign key associations that it has recreated. I hope this gets fixed in the following CTP.

Now, although deceptively easy through the designer, I have a gut-feeling that it's going to be best to actually understand all the XML mapping that is generated. Just like the WPF and WF designers immediately made me turn to learning Xaml and Xoml, I feel that this designer is going to force me to learn CSDL and CS mapping pretty quickly.

When opening the edmx file with the XML editor, quickly use ctrl-E-F to format everything. The designer creates very long lines.
The SSDL content is unimportant, since it represents the database and should not be tinkered with here.
The CSDL is as follows:

    <edmx:ConceptualModels>
      <Schema Namespace="EntityFrameworkTestModel1" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
        <EntityContainer Name="EntityFrameworkTestEntities4">
          <EntitySet Name="Person" EntityType="EntityFrameworkTestModel1.Person" />
        </EntityContainer>
        <EntityType Name="Customer" BaseType="EntityFrameworkTestModel1.Person">
          <Property Name="CustomerDiscount" Type="Int32" Nullable="false" />
        </EntityType>
        <EntityType Name="Employee" BaseType="EntityFrameworkTestModel1.Person">
          <Property Name="FunctionName" Type="String" Nullable="false" MaxLength="50" />
        </EntityType>
        <EntityType Name="Person">
          <Key>
            <PropertyRef Name="PersonID" />
          </Key>
          <Property Name="PersonID" Type="Int32" Nullable="false" />
          <Property Name="Firstname" Type="String" Nullable="false" MaxLength="50" />
          <Property Name="Lastname" Type="String" Nullable="false" MaxLength="50" />
        </EntityType>
      </Schema>
    </edmx:ConceptualModels>

Note a container with only one set: the Person set. Then the three types are defined. Only the Person type has a key identified, the Customer and the Employee do not!

The C-S mapping then, glues this model to the SSDL:

      <Mapping Space="C-S" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">
        <EntityContainerMapping StorageEntityContainer="dbo" CdmEntityContainer="EntityFrameworkTestEntities4">
          <EntitySetMapping Name="Person">
            <EntityTypeMapping TypeName="IsTypeOf(EntityFrameworkTestModel1.Person)">
              <MappingFragment StoreEntitySet="Person">
                <ScalarProperty Name="PersonID" ColumnName="PersonID" />
                <ScalarProperty Name="Firstname" ColumnName="Firstname" />
                <ScalarProperty Name="Lastname" ColumnName="Lastname" />
              </MappingFragment>
            </EntityTypeMapping>
            <EntityTypeMapping TypeName="IsTypeOf(EntityFrameworkTestModel1.Customer)">
              <MappingFragment StoreEntitySet="Customer">
                <ScalarProperty Name="PersonID" ColumnName="CustomerID" />
                <ScalarProperty Name="CustomerDiscount" ColumnName="CustomerDiscount" />
              </MappingFragment>
            </EntityTypeMapping>
            <EntityTypeMapping TypeName="IsTypeOf(EntityFrameworkTestModel1.Employee)">
              <MappingFragment StoreEntitySet="Employee">
                <ScalarProperty Name="PersonID" ColumnName="EmployeeID" />
                <ScalarProperty Name="FunctionName" ColumnName="FunctionName" />
              </MappingFragment>
            </EntityTypeMapping>
          </EntitySetMapping>
        </EntityContainerMapping>
      </Mapping>

Here we see the PersonID being mapped to either the CustomerID column or the EmployeeID column. Interesting!

In code, this allows us to do the following:

EntityFrameworkTestEntities4 context = new EntityFrameworkTestEntities4();


// inserting some
Person p = new Person();
p.Firstname = "Ruurd";
p.Lastname = "Boeke";
context.AddToPerson(p);

Customer c = new Customer();
c.Firstname = "Silvia";
c.Lastname = "Banana";
c.CustomerDiscount = 10;
context.AddToPerson(c);

Employee e = new Employee();
e.Firstname = "Ian";
e.Lastname = "Mort";
e.FunctionName = "Developer";
context.AddToPerson(e);

context.SaveChanges();

IQueryable<Person> persons =
from person in context.Person
select person;

foreach (Person person in persons)
{
Console.WriteLine("{0}, {1} is a {2}",
person.Firstname, person.Lastname, person.GetType().Name);
}

Console.ReadLine();

Did you notice that the context was first saved, before the Linq query was executed? It's easy to forget, but the query is executed on the database, not on a Union of objects in the database and in the context.

The output is as expected:

Ruurd, Boeke is a Person
Silvia, Banana is a Customer
Ian, Mort is a Employee

What I really like about this mapping strategy, is the fact that no discriminator column was needed. The system knows that an employee is an employee because of the existence of the record in the employee table. Let's quickly look at the generated query

SELECT
CASE WHEN (( NOT (([UnionAll1].[C2] = 1) AND ([UnionAll1].[C2] IS NOT NULL))) AND ( NOT (([UnionAll1].[C3] = 1) AND ([UnionAll1].[C3] IS NOT NULL)))) THEN '0X' WHEN (([UnionAll1].[C2] = 1) AND ([UnionAll1].[C2] IS NOT NULL)) THEN '0X0X' ELSE '0X1X' END AS [C1],
[Extent1].[PersonID] AS [PersonID],
[Extent1].[Firstname] AS [Firstname],
[Extent1].[Lastname] AS [Lastname],
CASE WHEN (( NOT (([UnionAll1].[C2] = 1) AND ([UnionAll1].[C2] IS NOT NULL))) AND ( NOT (([UnionAll1].[C3] = 1) AND ([UnionAll1].[C3] IS NOT NULL)))) THEN CAST(NULL AS int) WHEN (([UnionAll1].[C2] = 1) AND ([UnionAll1].[C2] IS NOT NULL)) THEN [UnionAll1].[CustomerDiscount] END AS [C2],
CASE WHEN (( NOT (([UnionAll1].[C2] = 1) AND ([UnionAll1].[C2] IS NOT NULL))) AND ( NOT (([UnionAll1].[C3] = 1) AND ([UnionAll1].[C3] IS NOT NULL)))) THEN CAST(NULL AS nvarchar(50)) WHEN (([UnionAll1].[C2] = 1) AND ([UnionAll1].[C2] IS NOT NULL)) THEN CAST(NULL AS nvarchar(50)) ELSE CAST( [UnionAll1].[C1] AS nvarchar(50)) END AS [C3]
FROM [dbo].[Person] AS [Extent1]
LEFT OUTER JOIN (SELECT
    [Extent2].[CustomerID] AS [CustomerID],
    [Extent2].[CustomerDiscount] AS [CustomerDiscount],
    CAST(NULL AS nvarchar(max)) AS [C1],
    cast(1 as bit) AS [C2],
    cast(0 as bit) AS [C3]
    FROM [dbo].[Customer] AS [Extent2]
UNION ALL
    SELECT
    [Extent3].[EmployeeID] AS [EmployeeID],
    CAST(NULL AS int) AS [C1],
    [Extent3].[FunctionName] AS [FunctionName],
    cast(0 as bit) AS [C2],
    cast(1 as bit) AS [C3]
    FROM [dbo].[Employee] AS [Extent3]) AS [UnionAll1] ON [Extent1].[PersonID] = [UnionAll1].[CustomerID]

A left outer join was done with a union of customer and employee. Also note the CASE statements in the main select statement.
I leave it up to you to decide if such SQL statements are okay in your environment. I see no problem with them but I can see them growing pretty fast.

Let's take a look at what happens if you only want your customers. The following Linq expression can be used:

IQueryable<Customer> customers =
from customer in context.Person.OfType<Customer>()
select customer;

When executed, the following SQL is executed:

SELECT
'0X0X' AS [C1],
[Extent1].[CustomerID] AS [CustomerID],
[Extent2].[Firstname] AS [Firstname],
[Extent2].[Lastname] AS [Lastname],
[Extent1].[CustomerDiscount] AS [CustomerDiscount]
FROM [dbo].[Customer] AS [Extent1]
INNER JOIN [dbo].[Person] AS [Extent2] ON [Extent1].[CustomerID] = [Extent2].[PersonID]

All in all very straightforward.

Wednesday, 02 January 2008 18:56:31 (Romance Standard Time, UTC+01:00)  #    Comments [11]  |  Trackback
 Tuesday, 28 August 2007

The new entityframework ctp was released. The official statement is here.
It includes the designer, so I'm very curious how this fares against nHibernate! Congratz to the team!

The Devguy does a summary of the features. Read this hilarious piece:

  • In previous CTPs the underlying provider connection was opened when the ObjectContext was constructed and held open for the life of the context—this would create issues, for instance, with databases where licensing was based on the number of concurrently open connections since the connection might be held open for an extended period of time—even when the connection is not being used.  The new model keeps the connection closed as much as possible while still appropriately dealing with transactions and avoiding promotion of those transactions from local to DTC where possible.

Really?

I mean, so, they now no longer keep the connection open all the time and instead have opted to close it when it's not in use..... because of licensing issues??

ROFL. I would think there are better reasons not to keep a connection open for too long, but that's just me.

;-)

Tuesday, 28 August 2007 13:23:20 (Romance Standard Time, UTC+01:00)  #    Comments [5]  |  Trackback
 Wednesday, 04 July 2007

I've been very interested in the progress of the entity framework. Recently, the June ctp was announced.

It boasts some new feature I had been waiting for, like the ability to detach the object from a context. This is necessary when you want to work in a disconnected manner. It would be fantastic if we would be able to retrieve a graph (spanning is now supported) and send it to a client, having the client change it and then reattach it to a new object context on the server. This would mean having to do change tracking on the client yourself, which does leave for more flexibility in your serialization format, as compared to using strange change tracking iEnumerable implementations that are out of your control.
This is the path Microsoft is taking. There is no real persistence ignorance yet, but they might be heading for a comfortable compromise.

Which brings me to nHibernate. The project I'm heading is a pretty big client-server application, which we are migrating to-wards a more flexible n-tier. We are rebuilding the client-side with WPF (for other reasons) and are implementing WF in the back-end to manage our processes. We have build our own naive OR-mapping layer on top of the datasets that were already in place. This has allowed me to delay having to make a choice for a real OR-mapper.
I have had some great experience with nHibernate, having used it since the 0.7 beta. Lately I have not had the opportunity to use it, but it seems the 1.2 release has added some major missing pieces of functionality like SPROC support and generics. I have some time left before I will have to choose between entity framework and nHibernate but I can already see it's going to be tough:

The generated code is ugly and although they have listened to the persistence ignorance argument, it seems too little, too late. Their V1.0 implementation might be an attempt to do it correctly, but if they had just listened earlier, their approach would have been much cleaner.
nHibernate is based on a proven concept and is very clean (although the code-base wasn't clean when I stepped through it ;-) ). It has a great community uptake. It, however, still lacks good modeling tools and it only has one dedicated programmer.

In the end, if Entity Framework turns out workable, it might be the better choice. It will get a big community (although a large part of that community will consist of programmers that don't even know of the alternatives), it has a big team of smart people working on it (although they needed quite a few tries to get it right) and it will have great visual tools (love it). In the end, most importantly, when I hire new people for the project, they are more likely to know EF then nHibernate. Is that a good reason though????

Wednesday, 04 July 2007 16:32:55 (Romance Standard Time, UTC+01:00)  #    Comments [12]  |  Trackback
 Tuesday, 13 June 2006

POCO power is announced by Roger Johansson, a lead developer of the NPersist OR-Mapper.
He writes: 'NPersist entities now supports 2 way databinding and edit cancels straight out of the box while still being fully POCO.
So as far as I know,
NPersist is the only .NET mapper capable of this while being POCO (at design time that is)'

The question I ask myself is, do you really want this? I admit I haven't used npersist for long, because I switched to nHibernate. But, having read Roger's blog for some time, I believe they are quite advanced in the proxy area, using IL.Emits all over the place for incredible speed (the only way to do it!). They certainly seem to have taken this path, giving as much luxury to the developer by doing all kinds of stuff dynamically. And yes, edit cancellation certainly seem like a nice feature to have out of the box. 2 way binding as well.

But then again, what if I want to switch to WPF? It supports the old way of propertynameChanged events, but I'd rather use the new Avalon flavor.
And I have built my own canceling, by using structs as the backing store of my properties. What if I want the 'loaded' state of my objects to also serialize, then I want my own solution where I can easily do that.

By doing too many things that are hard to follow for a developer, you will confuse them.
Most importantly, by doing too many things, you are locking developers into your technology.

I'm against that.

Then again, I'm also a bit jealous. I had to do all of that myself! I hope that their puzzle-framework uses a pluggable architecture, where you use a configuration file to 'plug in' capabilities to the proxy system, even allowing custom capabilities to be created. That would be awesome.

 

(If your into that kind of stuff, your best bet is the Castle framework. Check it out.)

Tuesday, 13 June 2006 12:19:48 (Romance Standard Time, UTC+01:00)  #    Comments [4]  |  Trackback