Update on developing a “mock” entity framework provider.

Just an update on the mock entity framework provider - the idea behind it is so that you can develop unit tests against a disconnected dataset, which you can setup in memory as part of the tests, so that the data is in a known state  - rather than hitting a live database.  To that end I’ve been experimenting a bit with the sample entity framework provider.

It seems that ObjectQuery<T> cannot be created without specifying a context and a query string.  Shame, otherwise I could simply mock the call to the NorthwindModel.Customers { get; } call, and return my own ObjectQuery<Customers> in place of the one the real provider would have returned.

It seems that it’s created in the entity framework code itself, where ther provider retrieves a datareader and converts it into an ObjectQuery of the class requested.

This means that my “dataset framework provider”  will have to receive the eSql query command and return a data reader from the dataset that matches the eSql query.  This data reader will be picked up by the framework code, which will convert it to an ObjectQuery<T> instance.

I found this quite useful “template data reader” on the msdn pages, where there is example code on how to create a data reader.  I plan to look into that a bit more.

I will also need to work out how the “dataset framework provider” will actually be given the dataset.

Once I have a working sample project, I’ll probably chuck it up on codeplex (if David Sceppa’s happy for me to, as it will use a large part of the sample entity framework code - I’ll have to check).

Technorati Tags: , ,

Entity Framework - Part 2 - Setting up a project and getting unit tests working

Follows on from part 1

As part of my investigations into the Entity Framework, I’ve setup a test project as a testbed.

You can download it here: EF Research project. You’ll need the Orcas beta 2 Pro (minimum), The Entity framework beta, and the Entity Framework ctp tools

Project Structure

EFResearch.sln initial structure

I created a blank solution and added a class library called EfNorthwindLibrary. In this project, I’ve created a EntityFramework model called CustomersModel.edmx (Right click, add new item, Select ADO.NET Entity Data Model and follow the wizard). For the moment, the Customers model contains only a reference to the Customers table - I will be expanding on this as I go through my posts.

Build Events

If you look at the Build Events of the project (Right click, Properties, Build Events), you will see a Post-build event command line which looks something like “%windir%\ Microsoft.NET\ Framework\v3.5\EdmxDeploy.exe” “$(ProjectDir) ” “$(TargetDir) “ - this tells the project to take the .edmx files contained within the library and output them as csdl, msl and ssdl files into the project output folder. Apparently, this will ultimately become an msbuild task, so it doesn’t need to be a post build event.

App.Config

If you now look in the App.Config, you will see a Connection String entry that looks something like: <add name=”NorthwindCustomersEntities” connectionString= “metadata=.\CustomersModel\CustomersModel.csdl |.\CustomersModel\CustomersModel.ssdl |.\CustomersModel\CustomersModel.msl; provider=System.Data.SqlClient; provider connection string=”Data Source=XPDEV\SQLEXPRESS;Initial Catalog=Northwind; Integrated Security=True” ” providerName=”System.Data.EntityClient” /> This contains three sections: a metadata section, a provider section and a provider connection string section.

The metadata section tells the framework where to find the csdl, msl and ssdl files, the provider section tells the framework which provider to use (this is where you can specify an alternative provider to the SqlClient - once they get written by third parties), and finally the provider connection string is a standard database connection string used by the provider. You can also specify all these settings in code if you prefer, but I’ll come to that another time.

CustomersModel.Designer.cs

You’ll see there is also a CustomersModel.Designer.cs file. If you have a look at it, you’ll see it contains two classes - NorthwindCustomersEntities of type System.Data.Objects.ObjectContext, and Customers of type System.Data.Objects.DataClasses.EntityObject. Both these are generated from the .csdl file.

The context class (NorthwindCustomersEntities) is how your application interacts with the model, and contains a collection of Customers in the form of a System.Data. Objects.ObjectQuery<Customers> property. The constructor for the class takes in a connection string, an EntityConnection object, or nothing, in which case it uses the connection string found in app.config with the same name (”NorthwindCustomersEntities”).

The Customers class represents a single Customer record, and contains the various customer properties (CompanyName, ContactTitle etc…). It’s a bit confusing, but the Customer table in the Northwind database is called Customers (plural, bad design), and the code generation just copies the names. We should be able to make it a singular that in the mapping at a later date.

The above two classes also contain a couple of utility method,

static Customers.CreateCustomers(customerId, companyName) - this returns a new customer instance.

and

NorthwindCustomersEntities.AddToCustomers(customers) - this adds a customer to the context.

These are partial classes, so we can extend them later with our own business logic.

Testing the generated classes and the mapping - Unit Test.

The Visual Studio Test system has made it’s way into the Pro version of Visual Studio 2008, so now I can run tests with the MS test framework, rather than nunit and testdriven.net (not that I don’t like nunit and testdriven.net - I wonder how this decision will affect testdriven.net, as it’s been a great alternative to paying full wack for the top end version of Visual studio).

The Test project is called EF_Test (right click solution, Add New Project, Test Project). We need to add a reference to EfNorthwindLibrary, and references to System.Data and System.Data.Entity.

We can create a new test such as:
[TestMethod]
public void TestConnectionStringWorks()
{
NorthwindCustomersModel.NorthwindCustomersEntities context = null;
context = new NorthwindCustomersModel.NorthwindCustomersEntities();
Assert.IsNotNull(context);
}

Run the test (On the menu, Text > Windows > Test View, and click Run Selection - don’t try to run the project - you can start a class library!)

Now, this will fail. We haven’t passed the NorthwindCustomersEntities a constructor, so it’s going to look in the App.config on the test project to find the connection (and it’s not there). Lets add an app.config to the project, and copy in the connection from EfNorthwindLibrary app.config.

Now it’s still going to fail, because the connection in app.config references the .csdl, .msd and .ssdl files, which our test can’t find. We’re going to have to edit the LocalTestRun.testrunconfig file to tell it to copy the three mapping files output by the EfNorthwindLibrary to the test output folder. We do that by double clicking the solution file LocalTestRun.testrunconfig, goto the deployment option and click Add File - browser to EfNorthwindLibrary\bin\Debug and select the three files we need. Now these three files will get copied to the test output folder.

Finally, make sure the metadata= in the app.config (for the test project) points to the files in the current folder, e.g. metadata=”.\CustomerModel.csdl ….” etc because the original app.config has the .csdl etc files in a subfolder rather than the current folder.

Now run the test - we should get a pass!

Once we have the project at this point, we can start to explore more.

Final note on unit testing

Further to this post^ on the msdn forums - when running unit tests, it should be possible to test business logic without hitting a real database (as this may require the database to be in a known state - a bad thing with unit tests). The usual method is to mock out the data access code. Anyway, that can’t be done at the moment, so I’m working on a “Mock” entity data provider, so that your unit tests would be able to provide the data that the business logic expects to receive. Something like:

  1. Create a dataset containing known data
  2. Pass that dataset to the mockEntityProvider
  3. Test the business logic of a class that querys the mockEntityProvider for the known data
  4. Verify the results of the business logic.

Watch this space. In the next post, I’ll be delving into the actual file structure and looking at adding an association to another table.

Entity Framework, Part 1 - The high level overview

LINQ to SQL (server)

I’ve been looking more into the new Microsoft Entity Framework since I found out that LINQ to SQL is a technology that can be used with Sql Server (and should perhaps be called LINQ to SQL Server).

LINQ to SQL Server translates the LINQ query to sql server SQL, and contacts the database where required (if the object isn’t already cached, for example).

Fortunately, LINQ as a technology in itself can be used with collections in general, and is not tied to a database at all (ie, you can create an IList<MyClass> and then query it using the LINQ syntax), and can be used with the Entity Framework (more on this later - lets get on with an overview).

Entity Framework

The traditional approach:

Diagram 1

Lots of coding time and effort tends to go into moving the data in the domain (eg, a Customer) back and forth between the application and the data store. The entity framework is designed to solve this problem.

NOTE: The examples I’m using at present represent a 1 - 1 mapping between a data table and the application classes (as LINQ to SQL server), but the entity framework is able to map a data table to multiple classes, or multiple data tables to a single class, and map across multiple databases - these are major differences between LINQ to SQL server and the entity framework.

Where the entity framework fits in:

Diagram 2

The entity framework, in essence, is a library that allows mapping between your classes and your database. This mapping is achieved with three files:

1. The .csdl file describes to the framework what your classes look like:

Diagram 3

2. The .ssdl file - tells the framework what your database looks like.

Diagram 4

3. The .msl file - tells the framework how to transform between the .ccsl and the .ssdl

Diagram 5

These three files are xml files. They need to be found by your application, so you need to provide a path to them (whether they are external files or embedded resources). There are a number of methods of creating these files

  • Type them in manually
  • Code generate them using the command line tool
  • Code generate them using the designer tools - this generates a .edmx file that contains all three files. The files are separated out into the output folder when you build.

When code generating using the command line tool, you can tell it to generate classes from the .csdl file (this is done automatically when using the designer tools) - these are partial classes and you can extend them as you wish.

LINQ to Entities

Now we get to the fun bit - The entity framework has it’s own query language (eSQL), very similar to SQL, that your code can use to retrieve classes from the database.

As I understand it (someone correct me if I’m wrong) the provider that you specify in the configuration (eg. System.Data.SqlClient) translates the eSQL to the specific sql required by the database. This means that a third party can provide their own entity framework provider that will work with their database.

Now, where as LINQ to SQL server translates the LINQ query to MS SQL, LINQ to Entities translates the LINQ query to eSQL - which is then translated into db specific sql by the provider. This means that you can use standard LINQ queries against the your entity framework model, with any database that has a provider (at present, only SQL).

Conclusion

This is only a high level overview based on my understanding so far. In the next part, I’m planning on creating a mapping between a basic database and some code.

Further resources:

If you’re interested in creating a managed provider, checkout David Sceppa’s blog post

Mike Taulty has some useful posts on the Entity Framework

TheServerSide has a good overview article (better than mine)