In my previous post I explained the concept and basics of Delegates. I’ll assume that there is an understanding of Lambda Expressions. The following content’s interest is close to just academic but, understanding it is key to really take advantage of Delegates and wonders a good implementation provides.
Simple Start
Let’s start with this simple delegate implementation:
delegate void StringVoidDelegate(string input);
As I exposed in my previous post, this defines a method signature where a string is received as a parameter and there is no return.
Since I’m in a Console Application I’ll implement some helpers to understand what is going on using the delegate just implemented:
static int CallCount = 0;
static StringVoidDelegate CWL = input => Console.WriteLine(++CallCount + " " + input);
A simple usage of this method can be:
With output:
Generic Delegate
Like any other generic capable object in .Net, delegates receive a type generically on implementation. Something like so:
delegate string ToString<T>(T obj);
If, for instance, we have a Person class like this:
class Person
{
public string Name { get; set; }
public DateTime Birthday { get; set; }
}
We can have a method compliant with ToString delegate signature like so:
ToString<Person> personToString = person => person.Name;
Which can be used like so:
ToString<Person> personToString = person => person.Name;
var jCleese = new Person { Name = "John Cleese", Birthday = new DateTime(1939, 10, 27) };
CWL(personToString(jCleese));
With output:
Stacking Delegates
Since calling a method with the assurance of its signature is so ‘OK’ we can easily stack delegates to be run consecutively, provided that the signature is the same. Same signature means all the delegates reference to de same implementation; delegates with same input and output type signatures but different implementation won’t be interoperable. Stacking and unstacking delegates is done using arithmetic ‘+’ and ‘–’ operators.
Adding adds the delegate on the right hand to the list of methods that will be called.
StringVoidDelegate Echo = input => CWL("Echo..." + input);
Echo += CWL;
Echo(personToString(jCleese));
With output:
1 Echo...John Cleese
2 John Cleese
So CWL will be run consequently after Echo with the same parameter.
Removing removes the last call to that method on the ‘stack’ if there is any. Say we have this parameter less delegate:
delegate void ParameterlessVoidDelegate();
This sequence:
ParameterlessVoidDelegate writeOne = () => CWL("One");
ParameterlessVoidDelegate writeTwo = () => CWL("Two");
ParameterlessVoidDelegate writeThree = () => CWL("Three");
ParameterlessVoidDelegate writeA = () => CWL("A");
ParameterlessVoidDelegate write = writeOne + writeA + writeTwo + writeA + (() => CWL("Four"));
write();
write -= writeA;
CWL("");
write();
write -= writeA;
CWL("");
write();
write -= writeA;
CWL("");
write();
Would have this output:
1 One
2 A
3 Two
4 A
5 Four
6
7 One
8 A
9 Two
10 Four
11
12 One
13 Two
14 Four
15
16 One
17 Two
18 Four
Composing results
When adding delegates with a return object, all methods are ran from left to right but only the last return is accounted for, all others are discarded.
Let’s take this signature:
delegate int IntToIntDelegate(int value);
The following code:
IntToIntDelegate baseAddingDelegate = value =>
{
CWL(value.ToString());
return value;
};
IntToIntDelegate AddOne = value => baseAddingDelegate(value + 1);
IntToIntDelegate AddTwo = value => baseAddingDelegate(value + 2);
var addAll = AddOne + AddTwo + (value => baseAddingDelegate(value + 3));
CWL(addAll(1).ToString());
(baseAddingDelegate is just a wrapper to shorten the code)
The output is this:
If the intension is to have the result of the application of all methods the implementation would have to look like so:
IntToIntDelegate AddOne = value => baseAddingDelegate(value + 1);
IntToIntDelegate AddTwo = value => baseAddingDelegate(value + 2);
IntToIntDelegate AddThree = value => baseAddingDelegate(value + 3);
IntToIntDelegate progressiveSum = value => AddOne(AddTwo(AddThree(value)));
CWL(progressiveSum(1).ToString());
And the result:
In Event Handling
Using delegates you can easily propagate method calling without having to reference methods in each others. For instance, having this methods:
RoutedEventHandler DoOneThing = new RoutedEventHandler((s, e) => { });
void ButtonHandler(object s, EventArgs args) { }
void DoAnotherThing() { }
This code is very OK and might be very useful:
button.Click += DoOneThing;
DoOneThing += ButtonHandler;
button.Click += (s, e) => DoAnotherThing();
.Net Action and Function
Just a quick note to say that our .Net Framework friends, since .Net 2.0, were kind enough to provide some common delegate implementation and, using generics, a short way to request for a certain signature.
Their implementation is as simple as this.
Action
public delegate void Action();
public delegate void Action<T>(T obj);
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
//etc.
That can be used like so:
var a = new Action<string, int, string>((s1, i, s2) => { CWL(s1); CWL(i.ToString()); CWL(s2); });
a("One", 2, "Three");
With this output:
Function
Is the same as Action but, at least, one generic type must be provide to serve as the return type. Something like so:
var f = new Func<int>(() => 3);
CWL(f().ToString());
Output:
Conclusion
Delegates that can help you simplify and encapsulate your code in an error safe way. The sky is the limit. I use them all the time to wrap generic asynchronous call handlings and stuff like that.
That’s all…hope it’s useful.
For the short life as a computer programmer I’ve enjoyed so far, the most miss, or not at all, understood feature of programming are delegates and, subsequently, handlers and events. I’ll try, here, to provide easily understandable way of looking at this mystery for so many ‘good’ programmers.
What is a delegate?
According to MSDN, a delegate is a type-safe and secure function pointer. To me this mean, a delegate is a definition of a method signature, i.e., it defines input and output parameter types for methods. Having this in mind, the following delegate definition:
delegate int StringToIntDelegate(string input);
…means that the methods compliant with this delegate, receive a string as input parameters and return an integer.
What is it worth?
By the first paragraph of this post, one might notice that the great majority of programmer don’t use (or so they think, as will see further down) delegates which means that they’re not essential for a computer programme to work. But, in the same direction, neither are classes and that’s not a place one wants to go. Delegates, like classes, provide strongly typed encapsulation and polymorphism whose purpose and consequences are the elimination of code redundancy and thus then probability of error and simplifies error correction.
An example
For instance, imagine we are implementing a class for form input field to wrap is properties and provide some validation. It would be nice to be able to generically but strongly-typed access a method that provides some validation. Bla, bla, bla…a little code might help.
The validator method would be, for our definition, a method that receives a string (that might be inserted by the user) and returns a boolean indicating if the value is valid. Something like so:
delegate bool ValidateStringDelegate(string input);
Having this definition at hand the implementation for an input field wrapper could look like this:
public class InputField
{
public string Value { get; set; }
public string Caption { get; set; }
public ValidateStringDelegate Validator { get; set; }
public bool IsValid { get { return Validator(Value); } }
}
A validator method could look like so:
bool MinimumLengthValidator(string value)
{ return value.Length > 3; }
An instance of InputField could look like so:
var field = new InputField();
field.Caption = "Property Caption";
field.Validator = new ValidateStringDelegate(MinimumLengthValidator);
And, at any time, there’s a safe and strongly typed way of checking if the field is valid, like:
if (field.IsValid)
Console.WriteLine("Incorrect input!");
else
Console.WriteLine("Input OK!");
Lambdas and delegates
I’d say lambdas and delegates are one of coding best friends ever. This happens because, as long as the delegate (the method signature, remember?) is defined a lambda expression is all that is needed to implement a method. Taking the example above, there are other shorter ways of instantiating an InputField. The following are valid and with the exact same outcome:
field.Validator = MinimumLengthValidator;
…
ValidateStringDelegate validator = (value) => { return value.Length > 3; };
field.Validator = validator;
…
field.Validator = (value) => { return value.Length > 3; };
…and, the one I would write…
field.Validator = value => value.Length > 3;
All these are possible because the signature of the method is established. By the time this line of code is reached, everybody knows that Validator property is to be a method that receives a string and returns a boolean.
Note that this:
var validator = (value) => { return value.Length > 3; };
is not valid and will result in compiler error because the compiler can’t tell what type value is supposed to be.
What about handlers and events?
As there is no chicken or egg, the event comes first.
Conceptually, and as the naming suggests, an event something that is suppose to be used (raised, so they say) when something happens. Technically it is just a delegate defined property like in the example above but whose setting is limited by the compiler. This means you can add methods to it but you can’t set it but, in my next post, I’ll explain delegate operations and the reason for this will be clear.
If will look at the customary implementation of an event in a class (or interface) it looks like so:
event HandlerType EventName;
Here, HandlerType is a defined delegate. In fact, our first delegate definition is just as valid as any other to use in the definition of an event:
event ValidateStringDelegate ValidateEvent;
This means that any handler assigned to this event must match the signature of ValidateStringDelegate.
Yes, although it is not the usual .Net approach, an event handler can have a return value. I’ll expose more on events in a future post but I’ll drop a simple implementation of the InputField class above that would be more useful in some scenarios, for instance, when the validation processing is to be called from some external object holding the InputField instance.
public class InputField
{
public string Value { get; set; }
public string Caption { get; set; }
public bool IsValid { get; private set; }
public event ValidateStringDelegate Validation;
public void Validate()
{
if (null == Validation)
IsValid = true;
else
IsValid = Validation(Value);
}
}
With this implementation, a form holding the InputField would just need to call Validate method and everything else would run its course in a safe and strongly-typed manner. Here, the naming ‘event’ makes less sense conceptually but I’ll get there in a future post.
Conclusion
Hope this made sense and that it may help at least one programmer doing better code.
“SQL Server Compact is not intended for ASP.NET development.”
Right…So you have this cool thing that allows you to have a SQL database in a hosting that only provides MySQL databases and such but you can’t use it. You got to be kidding me.
But, if really, really, really want it, there you go:
AppDomain.CurrentDomain.SetData("SQLServerCompactEditionUnderWebHosting", true);
Just put before the call to the database is made (Global.asax, etc.).
In my first post ever, I burped a view of Entity Framework. Too much information for a single post, very poorly organized, etc., etc. In this series I will try to make a more useful, readable, etc., approach so it can actually help anyone who plans on learning how to use it.
This intro will also serve as a host for all the links of the series as the posts are produced so, here they are:
- What is it?
- Persistency and SSDL
- CLR and CSDL
- Mapping and MSL
- Usage in CLR
- Usage in Data Services
- Conclusion
See you in the next post.
I lost two hours of my precious time because of this issue.
What?
I’m making the back bones of a website for a friend and, after cleaning all the designer like HTML and making sure it was lookalike in IE, Chrome, FireFox, Opera and Safari. Being such a simple subject, I’m using a simple ASP.Net Web Form (.Net 3.0) where I’m making my own JSON serialization for the response. Then, I started on implementing AJAX stuff with jQuery and that’s when things started to, amazingly get messy.
The code
My server side looked something like this:
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
var page = Pages.Find(p => p.Name == Request.QueryString["Name"]);
if (null != page) Response.Write(page.ToJSON());
Response.Flush();
Response.Close();
}
Pretty simple, hey? We’ll see about that.
My jQuery AJAX request looked something like this:
$.ajax({
url: "Server.aspx?Name=Home",
success: PopulatePage,
dataType: "json"
});
The occurrence
The DOM objects from the JSON sent by my server were OK in all browsers except for Chrome. Wow!
As I started to put alerts everywhere I first realized that Chrome was the only browser where XMLHtttRequest had no headers. Was this a cause or a symptom?
Furthermore, there was no responseText in XMLHttpRequest. Someone must be joking with me…
The solution
After some googling hitting everywhere but my issue, I managed to find the answer to my troubles in jQuery forums (link) where someone with a nickname that suggests he knows about Hi-Fi, kindly shared a link to where the cause and solution where explained.
It turns out that my good intensions to tell ASP handlers that I was done and that the response could be sent to the client by calling Response.Close() was causing, in Chrome, for the peer connection to be closed before any data was sent.
After a lot of code messing and try and miss and buffing, I just returned to my original code and commented the last line of Page_Load and the world was again turning.
PS
I had another minor issue, in this case, with Opera. I had a couple of span HTML elements where I set innerHTML with jQuery.html() method. Every other browser showed everything right except, as just stated, Opera. The cause was that these two span’s were self-closing elements, like so:
…and it looks like Opera doesn’t like it so I had to change it to:
<span id="idOfASpan"></span>
Now I really had a website W3C compliant in theory and visually as well.
I was implementing a communication with a device via RS232 and came across the possibility of not having any response. Just like every time one depends on someone else’s volatile response.
I looked around a bit and all I found was a little confusing and, as usual, very little generic. I put my hands on it and came up with this implementation that I now use, maybe, a little bit too much.
The Delegates
If you’re in .Net 2.0 Func<T> and Action are not yet implement. Actually, they’re just particular delegates that are so often used that were considered for .Net 3.0 (and posterior) inclusion. Their implementation is as follows:
public delegate T Func<T>();
public delegate void Action();
Implemention
The implementation couldn’t be simpler and is based on the ability to call delegates asynchronously with BeginInvoke and WaitHandle.WaitOne method provided by IAsyncResult.AsyncWaitHandle. Note that BeginInvoke and EndInvoke are provided by the C# compiler in it’s delegate keyword. If we at the IL generated by the compiler for Func<T> it becomes clear, even if you don’t know anything about IL:
.class auto ansi sealed nested public Func<T>
extends [mscorlib]System.MulticastDelegate
{
.method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed
{
}
.method public hidebysig newslot virtual instance class [mscorlib]System.IAsyncResult BeginInvoke(class [mscorlib]System.AsyncCallback callback, object 'object') runtime managed
{
}
.method public hidebysig newslot virtual instance !T EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
{
}
.method public hidebysig newslot virtual instance !T Invoke() runtime managed
{
}
}
If you’re wondering about System.MulticastDelegate…
So the implementation goes like so for methods with a return object:
static T RunMethodWithTimeOut<T>(int millisecondsToWait, T timeoutResult, Func<T> method)
{
var asyncResult = method.BeginInvoke(null, null);
if (!asyncResult.AsyncWaitHandle.WaitOne(millisecondsToWait))
return timeoutResult;
return method.EndInvoke(asyncResult);
}
And with void return, a boolean is returned indicating if the method ended which might be handy:
static bool RunMethodWithTimeOut(int millisecondsToWait, Action method)
{
var asyncResult = method.BeginInvoke(null, null);
if (!asyncResult.AsyncWaitHandle.WaitOne(millisecondsToWait))
return false;
return true;
}
Testing
For testing I implemented these two methods that use both implementations of RunMethodWithTimeout:
static string TestStringTimeout(int timeoutSeconds, int methodSeconds,
string timeoutResult, string methodResult)
{
return RunMethodWithTimeOut<string>(timeoutSeconds * 1000, timeoutResult,
() => { Thread.Sleep(methodSeconds * 1000); return methodResult; });
}
static bool TestVoidMethod(int timeoutSeconds, int methodSeconds)
{
return RunMethodWithTimeOut(timeoutSeconds * 1000,
() => Thread.Sleep(methodSeconds * 1000));
}
And run them in a console application testing all who-arrives-first scenarios:
static void Main(string[] args)
{
Console.WriteLine(TestStringTimeout(1, 2, "Timed out!", "++Success"));
Console.WriteLine(TestStringTimeout(2, 1, "Timed out!", "++Success"));
Console.WriteLine(TestStringTimeout(1, 1, "Timed out!", "++Success"));
Console.WriteLine();
Console.WriteLine(TestVoidMethod(1, 2) ? "++Success" : "Timed out!");
Console.WriteLine(TestVoidMethod(2, 1) ? "++Success" : "Timed out!");
Console.WriteLine(TestVoidMethod(1, 1) ? "++Success" : "Timed out!");
Console.ReadLine();
}
That’s wrap.
Heads up! Update
I was happily using this method when I started to run into some troubles. Now, it is quite obvious but I missed this very important issue: the method whose result is dismissed because it timed out has to be stopped.
In these cases, an overload providing and end method is most useful. Something like so:
static T RunMethodWithTimeOut<T>(int millisecondsToWait, T timeoutResult, Func<T> method, Action end)
{
var asyncResult = method.BeginInvoke(null, null);
if (!asyncResult.AsyncWaitHandle.WaitOne(millisecondsToWait))
{
end();
return timeoutResult;
}
end();
return method.EndInvoke(asyncResult);
}
And invoking would look something like this:
var isTimedOut = false;
var result = RunMethodWithTimeOut<string>(1000, "TimedOut",
() =>
{
string successResult;
do successResult = DoSomeProcessingThatMightNeverBeGood();
while (null != successResult && !isTimedOut);
return successResult;
},
() => { isTimedOut = true; });
What?
The clearer definition for ADO.Net Entity Frame (EF, from now on) I found on MSDN: “The ADO.NET Entity Framework enables developers to create data access applications by programming against a conceptual application model instead of programming directly against a relational storage schema.”
So, basically, EF wraps all the data access layer providing generic access code.
Why?
Why EF?
If you ever implemented a software that persisted data on a XML file or a SQL Server, you know the pain of implementing CRUD code either generic for all the implemented types or, much worst, by type. With EF you “only” need to implement one of the ends: CLR or persistency. The rest is provided by EF using, mainly LINQ.
Why Metadata?
“Meta”, among many other not relevant here interpretations, means form (as in shape or definition). In consequence, “metadata” will be a group of definitions that specify how data is shaped and, in the present case, also mapped.
Who?
Before putting the hands in the dough, lets see what are the files needed for this enterprise and what are their functions in the ordeal. Going, bottom to top, from persistency to CLR:
SQL Database
Could be another persistency provider but, in this case, I will use a Microsoft SQL Server 2008 R2 Express to host the persistency.
SSDL (Store Schema Definition Language)
A XML file that describes the persistency objects like tables, columns, views, etc.. It will be the persistency side of the EF model.
MSL (Mapping Specification Language)
A XML file that makes the bridge between the persistency model (SSDL) and the CLR model (CSDL) in the EF model.
CSDL (Conceptual Schema Definition Language)
A XML file that describes the CLR object implementation like classes, columns, etc.. It will be the CLR side of the EF model.
CLR (C#)
Could be another language but, please. It will hold the CLR implementation of the data objects to work with as well as the ObjectContext derived class that will provide CLR access to the persistency layer…we’ll get there eventually.
How?
I’d say the best way of starting any data driven software, and I’d risk to say as almost everything you set your mind to, is to start by conceptualizing what is really needed trying very very hard to forget anything I know about the actual technology or tools at hand. By default, that decision should only be made later. So, I’ll just describe what I want to display and persist.
The Data
To keep it simple, we’ll just have people with names, birthdays and pets that are animals with names, a species and a diet.
Outlining:
.Person
- Name
- Birthday
- Pets (that is a group of Animals)
.Animal
- Name
- Species
- Diet (that is a group of Food)
.Species
- Name
.Food
- Name
Species and Food are not declaratively specified but we can tell that these data are a type of their own.
Conceptual CLR
Now that we know what we want and knowing a little bit about object oriented programming, a CLR implementation of our data would look like this:
using System;
using System.Collections.Generic;
namespace EntityFrameworkByHand
{
public class Person
{
public string Name { get; set; }
public DateTime Birthday { get; set; }
public ICollection<Animal> Pets { get; set; }
}
public class Animal
{
public string Name { get; set; }
public Species Species { get; set; }
public Person Owner { get; set; }
public ICollection<Food> Diet { get; set; }
}
public class Species
{
public string Name { get; set; }
}
public class Food
{
public string Name { get; set; }
public string Description { get; set; }
}
}
CLR implementation won’t look exactly like this but it’s already pretty close.
Persistency
At this point, we can also have a pretty good idea of the best way to persist our data. As stated, I’ll be using a SQL Server, so we’ll have tables and columns. Not meaning to discuss here the best way to persist we’ll implement persistency in a way that better helps us understand EF. Here it goes:
CREATE TABLE [dbo].[Species](
[SpeciesId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](128) NOT NULL,
CONSTRAINT [PK_Species] PRIMARY KEY CLUSTERED ( [SpeciesId] ASC )
)
CREATE TABLE [dbo].[People](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](128) NOT NULL,
[Birthday] [datetime] NULL,
CONSTRAINT [PK_People] PRIMARY KEY CLUSTERED ( [Id] ASC )
)
CREATE TABLE [dbo].[Foods](
[Name] [varchar](128) NOT NULL,
CONSTRAINT [PK_Foods] PRIMARY KEY CLUSTERED ( [Name] ASC )
)
CREATE TABLE [dbo].[Animals](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](64) NOT NULL,
[SpeciesIdInAnimal] [int] NOT NULL,
[OwnerId] [int] NULL,
CONSTRAINT [PK_Animals] PRIMARY KEY CLUSTERED ( [Id] ASC )
)
CREATE TABLE [dbo].[AnimalsAndFoods](
[Food] [varchar](128) NOT NULL,
[AnimalId] [int] NOT NULL,
CONSTRAINT [PK_AnimalsAndFoods] PRIMARY KEY CLUSTERED ( [Food] ASC, [AnimalId] ASC )
)
ALTER TABLE [dbo].[Animals] WITH CHECK ADD CONSTRAINT [FK_OwnerInAnimals_PetsInPeople] FOREIGN KEY([OwnerId])
REFERENCES [dbo].[People] ([Id])
GO
ALTER TABLE [dbo].[Animals] CHECK CONSTRAINT [FK_OwnerInAnimals_PetsInPeople]
GO
ALTER TABLE [dbo].[Animals] WITH CHECK ADD CONSTRAINT [FK_SpeciesInAnimals_AnimalsInSpecies] FOREIGN KEY([SpeciesIdInAnimal])
REFERENCES [dbo].[Species] ([SpeciesId])
GO
ALTER TABLE [dbo].[Animals] CHECK CONSTRAINT [FK_SpeciesInAnimals_AnimalsInSpecies]
GO
ALTER TABLE [dbo].[AnimalsAndFoods] WITH CHECK ADD CONSTRAINT [FK_AnimalsAndFoods_Foods] FOREIGN KEY([Food])
REFERENCES [dbo].[Foods] ([Name])
GO
ALTER TABLE [dbo].[AnimalsAndFoods] CHECK CONSTRAINT [FK_AnimalsAndFoods_Foods]
GO
ALTER TABLE [dbo].[AnimalsAndFoods] WITH CHECK ADD CONSTRAINT [FK_AnimalsToFoods] FOREIGN KEY([AnimalId])
REFERENCES [dbo].[Animals] ([Id])
GO
ALTER TABLE [dbo].[AnimalsAndFoods] CHECK CONSTRAINT [FK_AnimalsToFoods]
GO
Some non-relevant SQL optimization scripts were obviously left out and, most importantly.
Before Modelling
Now that both ends of the equation are set and we took care of our clients needs and satisfied our database admin and his crazy ideas about how to keep data, we can start tying the knots. But first, it’s important to know that EF is all about: types, sets and associations. Where types hold the definitions of properties; sets are collections of objects of a given type; and associations are connection between types.
SSDL
As stated before, the SSDL file just describes the database schema. The “XML Element”>”Database Object” connections in SSDL :
- Property > database column
- EntityType > groups columns of the same table
- EntitySet > connects an EntityType to a database table
Being so, our SSDL could look like this:
<?xml version="1.0" encoding="utf-8" ?>
<Schema Namespace="SSDLNamespace" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008"
xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator"
xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
<EntityType Name="Person_SSDLType">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="int" Nullable="false" StoreGeneratedPattern="Identity"/>
<Property Name="Name" Type="varchar" MaxLength="128" Nullable="false"/>
<Property Name="Birthday" Type="datetime" Nullable="true"/>
</EntityType>
<EntityType Name="AnimalsDef">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="int" Nullable="false" StoreGeneratedPattern="Identity"/>
<Property Name="Name" Type="varchar" MaxLength="64" Nullable="false"/>
<Property Name="SpeciesIdInAnimal" Type="int" Nullable="false"/>
<Property Name="OwnerId" Type="int" Nullable="true"/>
</EntityType>
<EntityType Name="Species_Definition">
<Key>
<PropertyRef Name="SpeciesId"/>
</Key>
<Property Name="SpeciesId" Type="int" Nullable="false" StoreGeneratedPattern="Identity"/>
<Property Name="Name" Type="varchar" MaxLength="128" Nullable="false"/>
</EntityType>
<EntityType Name="FoodType">
<Key>
<PropertyRef Name="Name"/>
</Key>
<Property Name="Name" Type="varchar" MaxLength="128" Nullable="false"/>
<Property Name="Desc" Type="varchar" MaxLength="Max" Nullable="true"/>
</EntityType>
<EntityType Name="AnimalsAndFoods_Type">
<Key>
<PropertyRef Name="Food"/>
<PropertyRef Name="AnimalId"/>
</Key>
<Property Name="Food" Type="varchar" Nullable="false" MaxLength="128"/>
<Property Name="AnimalId" Type="int" Nullable="false"/>
</EntityType>
<EntityContainer Name="SSDLContainer">
<EntitySet Name="People_SSDLSet" EntityType="SSDLNamespace.Person_SSDLType" Table="People" Schema="dbo" store:Type="Tables"/>
<EntitySet Name="AnimalStoreSet" EntityType="SSDLNamespace.AnimalDef" Table="Animals" Schema="dbo" store:Type="Tables"/>
<EntitySet Name="SpeciesInStore" EntityType="SSDLNamespace.Species_Definition" Table="Species" Schema="dbo" store:Type="Tables"/>
<EntitySet Name="FoodSet" EntityType="SSDLNamespace.FoodType" Table="Foods" Schema="dbo" store:Type="Tables"/>
<EntitySet Name="AnimalsAndFoodsSet" EntityType="SSDLNamespace.AnimalsAndFoods_Type" Table="AnimalsAndFoods" Schema="dbo" store:Type="Tables"/>
</EntityContainer>
</Schema>
Notes:
. Association and AssociationSet elements are not present. The reason is that they are not needed. If you think about it you’ll realize that these elements represent database foreign key constraints and they are not needed and their existence doesn’t have to be known to write relational Transact-SQL, that is JOINs and the likes. This constrains are just database optimizations and guarantees of correct data insertion.
. Schema.Namespace and EntityType.Name are strictly for in-SSDL usage in EntitySet.EntityType.
. EntityContainer.Name, EntitySet.Name and Property.Name (which must match database column names) will be used in MSL file.
Final CLR
One thing that EF needs, as anyone would, for its tracking changing ability is to be able to distinguish uniquely each object of a certain type, which of course means have one of more properties that provide that distinction. Being that the case, these key properties must be included in the CLR implementation. Consequently, our CLR implementation will finally look like this:
using System;
using System.Collections.Generic;
namespace EntityFrameworkByHand
{
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? Birthday { get; set; }
public ICollection<Animal> Pets { get; set; }
}
public class Animal
{
public int Id { get; set; }
public string Name { get; set; }
public Species Species { get; set; }
public Person Owner { get; set; }
public ICollection<Food> Diet { get; set; }
}
public class Species
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Food
{
public string Name { get; set; }
public string Description { get; set; }
}
}
Notes:
. Person.Birthday was changed to Nullable<DateTime> because otherwise would result in runtime exceptions because DateTime is value type and, therefore, cannot be null.
CSDL
CSDL file should provide a representation of our CLR implementation. The principals on CSDL are almost the same as in SSDL with some slight nuances:
-EntityType > The class (must match CLR class name)
-Property > A property of a value type or of type string.
-NavigationProperty > A property whose type is an EntityType
-EntitySet > A collection of objects of a given EntityType
-Association > A relation between two EntityType indicating each side’s multiplicity (number of possible occurrences)
-AssocaitionSet > Defines in what EntitySet an Association should retrieve its objects
Having that in mind, our CSDL would look like this:
<?xml version="1.0" encoding="utf-8" ?>
<Schema Namespace="CSDLNamespace" Alias="Self"
xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
<EntityType Name="Person">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity"/>
<Property Name="Name" Type="String" Nullable="false" MaxLength="128"/>
<Property Name="Birthday" Type="DateTime" Nullable="true"/>
<NavigationProperty Name="Pets" Relationship="CSDLNamespace.PetsInPerson_OwnerInAnimal"
FromRole="PetsInPerson" ToRole="OwnerInAnimal"/>
</EntityType>
<EntityType Name="Animal">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity"/>
<Property Name="Name" Type="String" Nullable="false" MaxLength="64"/>
<NavigationProperty Name="Species" Relationship="CSDLNameSpace.SpeciesInAnimal"
FromRole="Dependent" ToRole="Principal"/>
<NavigationProperty Name="Owner" Relationship="CSDLNamespace.PetsInPerson_OwnerInAnimal"
FromRole="OwnerInAnimal" ToRole="PetsInPerson"/>
<NavigationProperty Name="Diet" Relationship="CSDLNamespace.FoodsInAnimals"
FromRole="FoodsInAnimals" ToRole="AnimalsInFoods"/>
</EntityType>
<EntityType Name="Species">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity"/>
<Property Name="Name" Type="String" Nullable="false" MaxLength="128"/>
</EntityType>
<EntityType Name="Food">
<Key>
<PropertyRef Name="Name"/>
</Key>
<Property Name="Name" Type="String" Nullable="false" MaxLength="128"/>
<Property Name="Description" Type="String" Nullable="true" MaxLength="Max"/>
</EntityType>
<Association Name="SpeciesInAnimal">
<End Role="Principal" Type="CSDLNameSpace.Species" Multiplicity="1"/>
<End Role="Dependent" Type="CSDLNameSpace.Animal" Multiplicity="*"/>
</Association>
<Association Name="PetsInPerson_OwnerInAnimal">
<End Role="PetsInPerson" Type="CSDLNameSpace.Person" Multiplicity="0..1"/>
<End Role="OwnerInAnimal" Type="CSDLNamespace.Animal" Multiplicity="*"/>
</Association>
<Association Name="FoodsToAnimals">
<End Role="FoodsInAnimals" Type="CSDLNamespace.Animal" Multiplicity="*"/>
<End Role="AnimalsInFoods" Type="CSDLNamespace.Food" Multiplicity="*"/>
</Association>
<EntityContainer Name="CSLDContainer" annotation:LazyLoadingEnabled="true">
<EntitySet Name="People" EntityType="CSDLNamespace.Person"/>
<EntitySet Name="Animals" EntityType="CSDLNamespace.Animal"/>
<EntitySet Name="Species" EntityType="CSDLNamespace.Species"/>
<EntitySet Name="Foods" EntityType="CSDLNamespace.Foods"/>
<AssociationSet Name="SpeciesInAnimal_AssociationSet" Association="CSDLNamespace.SpeciesInAnimal">
<End Role="Principal" EntitySet="Species"/>
<End Role="Dependent" EntitySet="Animals"/>
</AssociationSet>
<AssociationSet Name="PetsInPerson_OwnerInAnimal_AssociationSet"
Association="CSDLNamespace.PetsInPerson_OwnerInAnimal">
<End Role="PetsInPerson" EntitySet="People"/>
<End Role="OwnerInAnimal" EntitySet="Animals"/>
</AssociationSet>
<AssociationSet Name="FoodsToAnimals_AssociationSet" Association="CSDLNamespace.FoodsToAnimals">
<End Role="FoodsInAnimals" EntitySet="Animals"/>
<End Role="AnimalsInFoods" EntitySet="Foods"/>
</AssociationSet>
</EntityContainer>
</Schema>
Notes:
. Schema.Namespace will be used in MSL file for EntityTypes and Associations must be fully named.
. Association.End.Role will also be used in MSL.
MSL
Finally, we need to join SSDL with MSL to map our persistency with our CLR objects. The basic principals are as follows:
- EntityContainerMapping > a mapping between a SSDL and a CSDL EntityContainers.
- EntitySetMapping > a CSDL EntitySet.
- EntityTypeMapping > a CSDL EntityType.
- MappingFragment > a SSDL EntitySet.
It should look, something like this:
<?xml version="1.0" encoding="utf-8" ?>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs">
<EntityContainerMapping CdmEntityContainer="CSLDContainer" StorageEntityContainer="SSDLContainer">
<EntitySetMapping Name="People">
<EntityTypeMapping TypeName="CSDLNamespace.Person">
<MappingFragment StoreEntitySet="People_SSDLSet">
<ScalarProperty Name="Id" ColumnName="Id"/>
<ScalarProperty Name="Name" ColumnName="Name"/>
<ScalarProperty Name="Birthday" ColumnName="Birthday"/>
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="Animals">
<EntityTypeMapping TypeName="CSDLNamespace.Animals">
<MappingFragment StoreEntitySet="AnimalStoreSet">
<ScalarProperty Name="Id" ColumnName="Id"/>
<ScalarProperty Name="Name" ColumnName="Name"/>
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="Species">
<EntityTypeMapping TypeName="CSDLNamespace.Species">
<MappingFragment StoreEntitySet="SpeciesInStore">
<ScalarProperty Name="Id" ColumnName="SpeciesId"/>
<ScalarProperty Name="Name" ColumnName="Name"/>
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<AssociationSetMapping Name="SpeciesInAnimal_AssociationSet"
StoreEntitySet="AnimalStoreSet"
TypeName="CSDLNamespace.SpeciesInAnimal">
<EndProperty Name="Principal">
<ScalarProperty Name="Id" ColumnName="SpeciesIdInAnimal"/>
</EndProperty>
<EndProperty Name="Dependent">
<ScalarProperty Name="Id" ColumnName="Id"/>
</EndProperty>
</AssociationSetMapping>
<AssociationSetMapping Name="PetsInPerson_OwnerInAnimal_AssociationSet"
StoreEntitySet="AnimalStoreSet"
TypeName="CSDLNamespace.PetsInPerson_OwnerInAnimal">
<EndProperty Name="PetsInPerson">
<ScalarProperty Name="Id" ColumnName="OwnerId"/>
</EndProperty>
<EndProperty Name="OwnerInAnimal">
<ScalarProperty Name="Id" ColumnName="Id"/>
</EndProperty>
<Condition ColumnName="OwnerId" IsNull="false"/>
</AssociationSetMapping>
<AssociationSetMapping Name="FoodsToAnimals_AssociationSet"
StoreEntitySet="AnimalsAndFoodsSet"
TypeName="CSDLNamespace.FoodsToAnimals">
<EndProperty Name="AnimalsInFoods">
<ScalarProperty Name="Id" ColumnName="AnimalId"/>
</EndProperty>
<EndProperty Name="FoodsInAnimals">
<ScalarProperty Name="Name" ColumnName="Food"/>
</EndProperty>
</AssociationSetMapping>
</EntityContainerMapping>
</Mapping>
Finally
All we need to do is to have a class deriving from System.Data.Objects.ObjectContext (in System.Data.Entity.dll) that implements ObjectSet<T> properties of the EntitySets defined in CSDL. Something like so:
using System.Data.Objects;
namespace EntityFrameworkByHand
{
public class BHObjectContext : ObjectContext
{
private ObjectSet<Person> people;
public ObjectSet<Person> People
{ get { return people ?? (people = CreateObjectSet<Person>()); } }
private ObjectSet<Animal> animals;
public ObjectSet<Animal> Animals
{ get { return animals ?? (animals = CreateObjectSet<Animal>()); } }
private ObjectSet<Species> species;
public ObjectSet<Species> Species
{ get { return species ?? (species = CreateObjectSet<Species>()); } }
private ObjectSet<Food> foods;
public ObjectSet<Food> Foods
{ get { return foods ?? (foods = CreateObjectSet<Food>()); } }
}
}
Now what?
If you made it this far, I salute you! This whole post was written with no testing what so ever which means there must be tons of typos mainly in the code snippets. I will, soon, clean any eventual mistakes and provide a working Visual Studio solution. Thankfully, the exceptions throw by EF are usually very clarifying of what is going wrong. Cleaning this is a great exercise to get into EF metadata.
I will in the nearest future possible post more extensively on more specific subjects of EF like:
- Inheritance (all kinds of it);
- Special Association scenarios;
- WCF DataService usage of EF and its current limitations;
- What is missing?
- And/or any other subject you feel should be target.
Here I am, once again, with promise to expose content of interest, at least, to me. Mostly technical and programming stuff but not necessarily only.
If the various role players stay on their current routes, I’ll keep on privileging Microsoft development technologies for they provide, in my experience and understanding, the most coherent solutions and, by far, the best overall implementations. As always since I started the life of a computer programmer, I’ll keep on trying, at least once, whatever comes out regardless of branding and technology as well as some legacy goodies.
If ever you find something you’d like me to cover or have any doubt about what is exposed here, write a comment anywhere and I’ll try to keep up.
Having said that, the door is open, and so is the window so come right in.
Welcome! Will see how it goes.
”What will be, only when it will be, will be what it is.”
Alberto Caeiro (Fernando Pessoa)
Original quote: “O que for, quando for, é que será o que é”