Wednesday, November 07, 2012

Extend ASP.NET Entity Framework by Partial Classes

ASP.NET Entity Framework 4 can help link up entity objects to existing database resources. Let's say you have your database tables already setup and ready to use. On Visual Studio 2010, you can import databases tables into its Entity Model. Every column in the data table can be wrapped inside a class as a property. When you open up the model's designer cs class after the import, you'll the source code like this:
#region Entities
[EdmEntityTypeAttribute(NamespaceName="Model", Name="table1")]
public partial class table1 : EntityObject
    public int Id {get; set;}
    public string Name {get; set;}
But how would we extend this entity if we want to add new property to support this, the answer is using Partial Class:
public partial class ExistingClass {

    public string NewProperty {get; set;}
With the keyword "partial", you can extend the original class at any other places within the project. All those partial classes would just be compiled with the original ones so the class would support all those properties you mentioned in the partial classes.

So what if you want to encrypt a property within a usual entity class so it will be encrypted when being saved to the database? Let's create a partial class for this:

As you may notice the name of partial class must match the name of the original class.
public partial class table1 {

    //Let's say Name property will contain encrypted text

    //Open property to the public with no knowing of any encryption/decryption done on the fly
    public string ClearName{
            return decrypt(this.Name); //Decryption works here
            this.Name = encrypt(value); //This is where encryption takes place
The combination of private variable and public property can provide transparent encryption/decryption feature to the property in the original class. The entity object table1 can finally be saved to the data table "table1" with encrypted text in the column "Name" 

The only downside is that LINQ does not support this additional property like "ClearName" which is not possible to be translated from its complex data type to the primitive data type while generating valid SQL statements inside its gears. You'll see error messages whenever you involve this property in LINQ's conditional search statement, like:

var tables1_entities = Entities.table1.Where(p => p.ClearName == "Julia");

Obviously, "ClearName" property does not exist in the data table. It's just a property in the .NET partial class.

To get things work again, you need to isolate the additional property out of LINQ statement:

//Encrypt the search text first and put it into a variable
var SearchCondition = Encrypt("Julia"); 
//Search it by using encrypted text instead
var tables1_entities = Entities.table1.Where(p => p.Name == SearchCondition); 
Of course, for encryption, the search text must be exactly the same as the content in the data table. Therefore, it's not recommend to search encrypted text this way. You would search by using other clear text columns in the same data table to avoid any conflict like this.