Multiple database support with Entity Framework

by mosessaur| 18 August 2009| 18 Comments

Introduction

One of the features introduced in Entity Framework is being database independent. Which mean each database provider can support Entity Framework by implementing its provider.

This feature allows you build applications independent from the underplaying database provider. In this post I’m going to show how to build an application that support multiple databases using same conceptual model made by Entity Framework.

Entity Framework providers

Entity Framework is database independent. Each database provider could have its own Entity Framework provider. Currently there are several database provider who support the current version of Entity Framework that is released with .Net 3.5 SP1.

A list of Entity Framework providers can be found .

Entity Framework multiple database support sample

In this post, I am going to demonstrate a sample application (based on northwind database) that is going to support both SQL Server database engine and MySQL database engine.

MySQL Entity Framework provider (connector/net)

I am going to use is connector/net ADO.NET provider for MySQL. It is a free provider and open source built by MySQL .Net data provider team. The version I am using is a modified version (by me) of connector/net 6.0.3. At the time of writing this post current release is 6.0.4.

How to prepare your Entity Data Model for multi-database support?

In order to keep your conceptual model (CSDL) static and ready to be used with different databases you should make sure that your database schema is the same across all database engine you plan to support.

For example, Northwind database schema in SQL Server is the same as Northwind database in MySQL. There are differences in data types, for example uniqueidentifier doesn’t exists in current version of MySQL, however there is a replacement which could be varbinary(16). Also data types might differ in names but there representation in .Net is the same, for example there is bit in SQL server and boolean -tinyint- in MySQL can be mapped to Boolean -bool- in .Net. Schema includes views and stored procedures/user defined functions (names, parameters and return results)

As conclusion, you have to maintain your database schema across any engine you wish to use to keep your CSDL untouchable. However change in your storage schema in EDM (SSDL) is mandatory as we are going to see later.

Steps support multiple database providers using Entity Framework

Modifying the SSDL

First step would be preparing your database on the provider you wish to work with. In my case it is MySQL. Script of northwind database on MySQL is attached with this post.

Next step is to modify your SSDL! If you are using VS.Net 2008 SP1 Entity Framework designer then your probably got a EDMX file for the generated EDM. the EDMX combines all CSDL,SSDL and MSL in it. You need just to have another SSDL file for your new database under MySQL.

To proceed with this, just create another file with and call it for example Northwind.MySQL.ssdl. Set its Copy to Output Directory option to Copy Always. Then add the following at the top of the new document (XML root):
<?xml version="1.0" encoding="utf-8"?>
Then follow the following steps to extract (copy) SSDL from the generated EDMX

  1. Right click on your EDMX file “Northwind.edmx” and select “Open With…” from the context menu.
  2. From “Open With” dialog select XML Editor (make sure you already saved your EDMX). An XML view of your EDMX will appear.
  3. Find an XML comment <!--SSDL content --> where you will find underneath it a StorageModels element.
  4. Copy the content of Schema element under StorageModels element (without StorageModels element)
  5. Past what you just copied into Northwind.MySQL.ssdl

After you got your copy of SSDL file you’ll need to modify it. Lets walkthrough where the modification should take place.

The Schema element contain several attributes. 2 of them should be changes to a new values. Provider and ProviderManifestToken attributes.

  1. Provider attribute specify the underlying .Net data provider name that should be used for this storage schema (SSDL). So change its value to “MySql.Data.MySqlClient”.
  2. used to load the provider manifest for offline scenarios.There is no specific schema for the token; it is up to the provider to choose the minimum information needed to identify a manifest without having to open a connection to storage. You’ll notice in most cases it shows a version of the underlying database engine. So in MySQL case it should be “MySQL5”.

The final output of Schema element should look like this:

<Schema Namespace="NorthwindModel.Store" Alias="Self" 
   Provider="MySql.Data.MySqlClient" 
   ProviderManifestToken="MySQL5" 
   xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" 
   xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">...
</Schema>

The next changes are related to the storage schema (schema name and data types).

On each EntitySet element there is an attribute called schema. In case of SQL Server this attribute is set to the related table schema. In MySQL you just need to set this attribute to the name your database.

<EntitySet Name="Categories" .... Schema="northwind" />

Note: in the above code snippet part of code is omitted for clarification.

Now under each EntityType element there are several Property elements. Each Property element maps to a database table column with the same name. And of course should be of the same data type. That is why there is a Type attribute for each Property element.

Sometimes (depending on provider mapped data types) you’ll need to change this Type attribute for several Property elements. For example MySQL provider doesn’t recognize the data type ntext which supported by SQL Server. However another data type could be used such as MEDIUMTEXT or LONGTEXT.

You should correct such things in your Schema EntityTypes Properties. Happy that Nothwind isn’t complicated at all and most of the data types used with it are common between both engines. I just had to change few types.

Now we are done with SSDL modification, and time to move to Connection String.

Modifying Connection String

I left this to the end. Changing connection string would the most easy task. I highly recommend to read about .

The connection string generated to you would be something like this:

<connectionStrings>
 <add name="Northwind" 
  connectionString="metadata=res://*/NorthwindModel.csdl|res://*/NorthwindModel.ssdl|res://*/NorthwindModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\SQLExpress;Initial Catalog=Northwind;Integrated Security=True;&quot;" 
  providerName="System.Data.EntityClient" />
  </connectionStrings>
A change to connection string is mandatory to specify different ssdl file, provider and provider connection string. All these information is provided above as a value to connectionString attribute of add element.

A modified Connection string would be like this:

<add name="NorthwindEntitiesMySQL"
 connectionString="metadata=Northwind.MySql.ssdl|res://*/NorthwindModel.csdl|res://*/NorthwindModel.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;user id=root;password=Pa$$w0rd;persist security info=True;database=northwind&quot;" 
 providerName="System.Data.EntityClient" />

Note that metadata value is changed. It now points to Nothwind.MySQL.ssdl file that is not part of assembly resource, but a file on the same folder of the executing assembly. Also provider value change to MySql.Data.MySqlClient and provider connection string is changed to “server=localhost;user id=root;password=Pa$$w0rd;persist security info=True;database=northwind”.

Note that you also can choose to make your Northwind.MySQL.ssdl as part of assembly resources by changing the Build action of the file to be Embedded Resource and Copy to Output Directory option to Do not copy. In this case your metadata value will be “metadata=res://*/Northwind.MySql.ssdl|res://*/NorthwindModel.csdl|res://*/NorthwindModel.msl”.

Now have a look at the attached sample project. Notice that there is no change in code that access the entity framework, just changing the connection string to use another one.

Conclusion

Being database independent is a great feature that comes out of the box with Entity Framework. Being able to switch to another database engine without touching your code is one big feature I admire myself. Just changes in SSDL and connection string and you are done to go live on another database with your application.

We already applied this practically with . Now supports repositories and models that are implemented with current version of Entity Framework. -with appreciation to Entity Framework- supports both SQL Server and MySQL. No code change –check it yourself-

Feel free to or the attached sample to explore this cool feature.

Comments

trackback
DotNetShoutout on 8/14/2009 9:50 AM Moses' Blog | Multiple database support with Entity Framework

Thank you for submitting this cool story - Trackback from DotNetShoutout
trackback
DotNetKicks.com on 8/14/2009 9:53 AM Multiple database support with Entity Framework

You've been kicked (a good thing) - Trackback from DotNetKicks.com
trackback
progg.ru on 8/15/2009 3:25 AM Поддержка множественных баз данных с Entity Framework

Thank you for submitting this cool story - Trackback from progg.ru
pingback
blog.cwa.me.uk on 8/15/2009 5:40 AM Pingback from blog.cwa.me.uk

Reflective Perspective - Chris Alcock  » The Morning Brew #415
trackback
DotNetBurner - ADO.NET on 8/15/2009 3:50 PM Moses' Blog | Multiple database support with Entity Framework

DotNetBurner - burning hot .net content
Julie LErman
Julie LErman United States on 8/15/2009 5:24 PM Nice job, Moses. It is definitely easy when the schemas of your different databases are so nicely aligned.

If they weren't I'd probably generate an SSDL for the new database and manually map it to the existing CSDL. That would okay to do if the databases were still close.

If they were *very* different, e.g. Northwind and Adventureworks where your first hurdle is that NW's CustomerIDs are chars, then you are in for some hairpulling.

Julie
mosessaur
mosessaur Egypt on 8/16/2009 4:21 AM Thank you Julie for comment. I would like to add that if your provider is buggy, or isn't complete that would extra pain. e.g with MySQL I face few issues with Guid. MySQL doesn't support Guids, instead we can use binary(16) or char or varchar with proper size.
Some providers automatically map binary(16) to Guids but some don't. And some for get all about it!
Personally I had to modify connector/net to fix few issues.

I did excatly as you mentioned by generating SSDL. I did that for KiGG. I generated the whol EDMX and took a copy of SSDL and start the manual mapping. Lucky enough that wasn't too much work.

I happy that finally I got this post live! It was supposed to be live last month after our user group gathering.

pingback
blog.garypretty.co.uk on 8/21/2009 4:01 PM Pingback from blog.garypretty.co.uk

Entity Framework v2 Articles »  Gary Pretty’s Blog
Josh Tucholski
Josh Tucholski United States on 8/22/2009 4:58 AM Moses,

I am struggling trying to do this. My csdl, ssdl, and msl  files are set to Copy Always and when referencing their file name in the bin folder I get the following error:

The server encountered an error processing the request. The exception message is 'The specified metadata path is not valid. A valid path must be either an existing directory, an existing file with extension '.csdl', '.ssdl', or '.msl', or a URI that identifies an embedded resource.'. See server logs for more details.

Did you run into anything like this? Could it be because we have it configured as an application and not a web project?
mosessaur
mosessaur Egypt on 8/23/2009 1:29 PM I don't remember if I run into this before or not. But tell this is a compilation error or runtime error.
If runtime error, could you please show me your connectionstring.
As I understand is that you now copy your meta data into output directory, and it is not part of assembly resources anymore right?
Maybe it is an issue with connectionstring and paths to meta data files need to be modified in it.
Josh Tucholski
Josh Tucholski United States on 8/25/2009 3:07 PM Ugh, I was using the wrong path to the files. Stupid error. Was looking at bin/File.csdl, bin/File.ssdl, and bil/File.msl.  Needed to include the ~ before each of the file paths.
mosessaur
mosessaur Egypt on 8/25/2009 9:04 PM Don't worry it is a common mistake that we all might fall in first time. Good you cought it anyway.
Giovane
Giovane Brazil on 8/29/2009 12:27 AM Hi moses

This is the best article for support and usage of EF in many DataBses. I am try to deploy one web applications that uses EF and MySQL but still see this error's int the remote server.

error 0040: The Type bool is not qualified with a namespace or alias. Only PrimitiveTypes can be used without qualification.
error 0040: The Type usmallint is not qualified with a namespace or alias. Only PrimitiveTypes can be used without qualification.

In my Developer machine, it's works perfectly. In the server that I need to deploy dont work.

any suggestion?
Muhammad Mosa
Muhammad Mosa Egypt on 8/29/2009 1:05 AM You might need to check the version of MySQL on your deployment server. Also note the connector/net has some bugs if you are using the original one released by MySQL.

bool is supposed to be supported by the provider but not sure about usmallint.
Did you also upload your connector/net to the deployment server bin? if you not then upload your working version?
This error is related to the provider or MySQL version I guess
Giovane
Giovane Brazil on 8/29/2009 1:29 AM Thank's for the reply,

I'am using the .NET provider developer for the MySQL in the version 6.1 (dev.mysql.com/downloads/connector/net/6.1.html) I upload all the files need to the application run in the bin folder, includes the provider.

I test in my developer machine the application and configures to use the remote db, and It's working perfectly. But in the remote application server, does't work with the same config. I've get the error.

In remote server host, the MySQL is 5.1.34 x86_64 pc-linux-gnu. In my developer machine It's is 5.1.35 x32. That is a problem?

I think that I need to try that you read in this article and see the results.

Do you use other provider for MySQL? Can you send-me?
pingback
beyondnet.codesol.info on 11/12/2009 8:25 AM Pingback from beyondnet.codesol.info

Recursos para Microsoft Entity framework « BeyondNet
trackback
Infinite Codex on 5/18/2010 3:26 AM Preparing an Entity Framework model for multi provider support

Preparing an Entity Framework model for multi provider support
pingback
306.computeronlinebingo.com on 5/20/2010 5:42 AM Pingback from 306.computeronlinebingo.com

P35 P3600 Van Oem Gas, Ip35 P2500 Bus Aftermarket
Comments are closed