Entity Framework vs Linq to SQL vs Repository Factory: Performance

by Jesse 12. July 2010 23:04

It has been long time since my last post. It really dues to the heavy workload in my job(I hope my manager can see thisTongue out) and my health problem. And with the release of VS2010 and ADO.NET 4.0, I am very interesting to know what is the "best" "orm" I can use in .net world now. I have quoted "best", because I dont want to argue with anyone which one is best for you. I also quoted "orm", because repository factory is not really an orm.

First I'd like to say a little bit of my background in using ORM. In the old days(before microsoft causes any chaos by releasing two unfinished two productions, linq to sql and entity framework), I was really interested in nhibernate, the biggest reason is that it supports many databases and mono(.net framework on linux). But honest speaking, I dont believe nhibernate is a good choice in any medium to large commercial projects. At least your DBA will never let the dynamic queries generated by nhibernate to select, insert or delete tables. Especaily in the production environment of SQL Server, stored procedures are pretty much everything you can access from code. It basically makes nhibernate useless. However, in certain projects, it does add a owo-factor, such as CMS. I created a nhibernate CMS in my previous job about 3 years, it heavily reduced the cost of hosting by using linux mono + mysql, and it also gives marketing people a strong sale point. Because it can be easily fitted into clients' exist IT infrastructure, using exist server, no matter linux or window, using exist db with many choice. If you comes to this page to find a CMS, you may interest to have a look at two open-source nhibernate CMS. Cuyahoga and Eucalypto.

Other ORM I looked at, NBear is another good one. But it apparently dead, the last update in sourceforge for this project was two years ago. What a shame!!! There are many other ORMs, I dont want to list them all, because as you know, I always can find a reason for no using it.Smile

Back to our main story, repository factory is a microsoft product (kind of). And released by Microsoft pattern & practice team. It is a great light-weight "ORM". After all, everything I need is a mapping system using stored procedure. Support different database? nope, but the chance of my company changing database is very low, especially after spending 50k+ on license. Support mono? nope, but maybe nobody else knows what mono project is. :p. So it is from microsoft and it does the job. It is a perfect little tool!! Until VS2008 coming out. The GUI tools did not support vs2008. But a separate team release a vs2008 version, and I have to compile from source code in order to fix some bugs. Now vs2010 is released, I think it is a good time to rethink DAL and possible a different ORM to replace. 

Linq to SQL and Entity Framework becomes two top choices to me. The reason is simple, firstly I dont want to pay, this push PLINQO (Linq to SQL extension, need CodeSmith, paidware!!!) and XPO out my choice. Secondly they comes from microsoft(it may not be a good reason, but keep the technologies used from the heads of same group people wont be a bad idea). I did a little search on google, and I found out there were quite a lot of poeple discussing the performance of these two ORM. So how much performance penalty will I have for using them? I decided to do a small test by myself. 

The test project is simple. A simple database with three columns, TSQL code shown below:

USE [TestDb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Table_1](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Description] [ntext] NULL,
CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

 

Five store procedures for insert, select on primary key, select on index key, update and delete. 

Create L2S dbml, EFv4 edmx using vs2010. I did not do any optimisations, there are a few performance tips you can find from google. But I personally wont bothered to use them in this test. AS repository factory GUI tool does not work with vs2010, I copied the code from previous project and amend it.

The test result is VERY interesting!

1. I know the first call to EF is slow due to generate views, but the first call to repository factory(RF) is almost as slow as EF

2. I read some post said L2S is slow on inserting, but actually it is not bad

3. L2S and EF on inserting are almost same

4. L2S selecting is slowest

5. RF and EF on selecting are almost same, which takes almost 2.5 times more time comparing with ADO.NET

Here is the result from two runs:

Run 1:
RF Insert Test: 1
Time used: 115
EF Insert Test: 1
Time used: 114
L2S Insert Test: 1
Time used: 14
ADO Insert Test: 1
Time used: 8
RF Insert Test: 1000
Time used: 797
EF Insert Test: 1000
Time used: 994
L2S Insert Test: 1000
Time used: 897
ADO Insert Test: 1000
Time used: 412
RF Select Test(PK): 1000
Time used: 259
EF Select Test(PK): 1000
Time used: 230
L2S Select Test(PK): 1000
Time used: 396
ADO Select Test(PK): 1000
Time used: 101
RF Select Test(Index): 1000
Time used: 270
EF Select Test(Index): 1000
Time used: 236
L2S Select Test(Index): 1000
Time used: 406
ADO Select Test(Index): 1000
Time used: 118

Run 2:
RF Insert Test: 1
Time used: 59
EF Insert Test: 1
Time used: 88
L2S Insert Test: 1
Time used: 11
ADO Insert Test: 1
Time used: 1
RF Insert Test: 1000
Time used: 725
EF Insert Test: 1000
Time used: 877
L2S Insert Test: 1000
Time used: 800
ADO Insert Test: 1000
Time used: 538
RF Select Test(PK): 1000
Time used: 246
EF Select Test(PK): 1000
Time used: 241
L2S Select Test(PK): 1000
Time used: 381
ADO Select Test(PK): 1000
Time used: 100
RF Select Test(Index): 1000
Time used: 263
EF Select Test(Index): 1000
Time used: 245
L2S Select Test(Index): 1000
Time used: 393
ADO Select Test(Index): 1000
Time used: 118

Unit: ms

In summary, I think the overall performance of EF is not as bad as I think. I know it is a still a simple test, with a lot more complex object and mapping, it may comes a totally different result. But this test still give me a little bit confidence to try EF in next project.

I will attach the test code later, and I do like to know what's in your mind. Please do comment.

 

Bouncy Castle C#

by Jesse 29. July 2009 11:54

It has been really long time since my last post. And finally I get a few minutes to write this post on using BouncyCacle encryption in C#, hopefully it can help some one.

BouncyCastle is a encryption library widely used in Java, and has been porting to C# ages ago. But due to lack of documentation, I believe many people including myself have much trouble on implement any encrypt/decrypt functions by using it. Right, let's start.

 

First of all, you need to get BouncyCastle library from its website on http://www.bouncycastle.org/csharp/. It is not necessary to get the source code. Also, there are two type of binary format libraries you can download. One is with IDEA, and another is not. If you dont know which one you need, just download the one without IDEA. As IDEA is patented in many country, so you must be more careful when choosing to use.

My implementation consist of two  parts: block cipher encryption engine, and encryption/decryption interface.

BCEngine class (Block cipher engine)

public class BCEngine
    {
        private readonly Encoding _encoding;
        private readonly IBlockCipher _blockCipher;
        private PaddedBufferedBlockCipher _cipher;
        private IBlockCipherPadding _padding;

        public BCEngine(IBlockCipher blockCipher, Encoding encoding)
        {
            _blockCipher = blockCipher;
            _encoding = encoding;
        }

        public void SetPadding(IBlockCipherPadding padding)
        {
            if(padding != null)
                _padding = padding;
        }

        public string Encrypt(string plain, string key)
        {
            byte[] result = BouncyCastleCrypto(true, _encoding.GetBytes(plain), key);
            return Convert.ToBase64String(result);
        }

        public string Decrypt(string cipher, string key)
        {
            byte[] result = BouncyCastleCrypto(false, Convert.FromBase64String(cipher), key);
            return _encoding.GetString(result);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="forEncrypt"></param>
        /// <param name="input"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        /// <exception cref="CryptoException"></exception>


        private byte[] BouncyCastleCrypto(bool forEncrypt, byte[] input, string key)
        {
            try
            {
                _cipher = _padding == null ? new PaddedBufferedBlockCipher(_blockCipher) : new PaddedBufferedBlockCipher(_blockCipher, _padding);
                byte[] keyByte = _encoding.GetBytes(key);
                _cipher.Init(forEncrypt, new KeyParameter(keyByte));
                return _cipher.DoFinal(input);
            }
            catch (Org.BouncyCastle.Crypto.CryptoException ex)
            {
                throw new CryptoException(ex);
            }
        }
    }

 

The encryption/decryption interface:

public string AESEncryption(string plain, string key, bool fips)
        {
            BCEngine bcEngine = new BCEngine(new AesEngine(), _encoding);
            bcEngine.SetPadding(_padding);
            return bcEngine.Encrypt(plain, key);
        }

        public string AESDecryption(string cipher, string key, bool fips)
        {
            BCEngine bcEngine = new BCEngine(new AesEngine(), _encoding);
            bcEngine.SetPadding(_padding);
            return bcEngine.Decrypt(cipher, key);
        }

 

You can easily change the BouncyCastle engine to Blowfish, DES, TripleDES, TwoFish, etc.

Make "Repository Factory" work on VS 2008

by Jesse 5. June 2009 13:33

I am writing another post at the same time to compare several MS ORM technic. Put the result first, I finally decide to use "Repository Factory". Well, it is NOT really a ORM, but a code generator like "MyGeneration". The reason I like it is: 1. it is open-source. it is very important if you want to use a long-last technic, and not need to worry about MS abandoning it during your projects are still going. 2. it is light-weight. comparing ADO.NET EF, it doesnt eat into your performance lots. There are so many reason I want to use it, even Patterns & Practice team gave up this project.

I download the source code from https://RepositoryFactory.svn.codeplex.com/svn, the last commition is Feb this year! The good news, or say best news, is the solution is compilable. But the bad news is it is not working!!!! I can tell the code in SVN trunk is a incomplete/bugy copy of RF. You have to change couple things to make it. The issues mentioned in below posts on Codeplex are still there, I put my patch in or find a workaround.

http://repositoryfactory.codeplex.com/Thread/View.aspx?ThreadId=32194
http://repositoryfactory.codeplex.com/Thread/View.aspx?ThreadId=46567

The main changes are done in "t4" files (template file, Im interesting to know where the name t4 comes from if anyone knows). Download them as you will, and use it as your risk. If you know other fixs, please do leave comments. It will benifit all of us.

Repository Factory VS 2008 Fix.rar (8.13 kb)

Fix W3C validation failure on ImageButton control (Server-wise)

by Jesse 18. May 2009 19:55

Recently runs into a problem on passing validation my .NET pages on W3C validator(http://validator.w3.org). Generally speaking the HTML code rendered from ImageButton control contains a invalid html tag border="0" which caused failure on passing XHTML 1.0 Transitional check.

Microsoft claimed it is not their issue, as it is not appear in "View code" of IE, which sounds more like an excuse to me. Dig several pages in google, one guy in asp.net forume suggested to use app_browser file which is working for me. Following is my w3c.browser file which sits in ~/App_Browsers folder


<browsers>
    <browser id="W3C" parentID="default">
        <identification>
            <userAgent match="^W3C_Validator" />
        </identification>

        <capture>
            <userAgent match="^W3C_Validator/(?'version'(?'major'\d+)(?'minor'\.\d+)\w*).*" />
        </capture>

        <capabilities>
          <capability name="browser" value="w3cValidator" />
          <capability name="majorversion" value="${major}" />
          <capability name="minorversion" value="${minor}" />
          <capability name="version" value="${version}" />
          <capability name="w3cdomversion" value="1.0" />
          <capability name="xml" value="true" />
          <capability name="tagWriter" value="System.Web.UI.HtmlTextWriter" />
        </capabilities>
    </browser>
</browsers>

However, there are many websites running on my server, it is not a enjoyable jobs to copy it to every website. A server-wise solution will be a big time-saver. Read the post about "Browser Definition File Schema" (http://msdn.microsoft.com/en-us/library/ms228122.aspx) carefully, I mean line by line and word by word. You may find following paragraph

However, if changes are made to .browser files in the %SystemRoot%\Microsoft.NET\Framework\version\CONFIG\Browsers directory, you must manually recompile the application by using the %SystemRoot%\Microsoft.NET\Framework\version\aspnet_regbrowsers.exe tool

Haha, this sounds like a server-wise solution. I copied my w3c.browser to both C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers and C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\CONFIG\Browsers, if you cannot find the second folder, you may be running on a 32 bit system, so don't need to worry about it. And the last thing needs to do

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regbrowsers.exe -i

The assembly will automatically installed into GAC. ^_^

Just out of curiosity, I reflected the code aspnet_regbrowsers generated. If you are a "dead cat" like me, here is the code

private bool W3cProcess(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
{
    IDictionary capabilities = browserCaps.Capabilities;
    string target = browserCaps[string.Empty];
    RegexWorker worker = new RegexWorker(browserCaps);
    if (!worker.ProcessRegex(target, "^W3C_Validator"))
    {
        return false;
    }
    worker.ProcessRegex(browserCaps[string.Empty], @"^W3C_Validator/(?'version'(?'major'\d+)(?'minor'\.\d+)\w*).*");
    capabilities["browser"] = "w3cValidator";
    capabilities["majorversion"] = worker["${major}"];
    capabilities["minorversion"] = worker["${minor}"];
    capabilities["version"] = worker["${version}"];
    capabilities["w3cdomversion"] = "1.0";
    capabilities["xml"] = "true";
    capabilities["tagWriter"] = "System.Web.UI.HtmlTextWriter";
    browserCaps.AddBrowser("W3C");
    this.W3cProcessGateways(headers, browserCaps);
    bool ignoreApplicationBrowsers = false;
    this.W3cProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps);
    return true;
}

protected virtual void W3cProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps)
{
}

protected virtual void W3cProcessGateways(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
{
}

Good post about BlogEngine.NET

by Jesse 8. May 2009 11:14

BlogEngine .NET is getting interested me. Believe or not, it uses quite a lot advanced coding technic, such as MVC, provider-based model, open search, extensible api, etc.

If you are interested to know more, and you can read chinese, try the following page. or using google translate tool, you won't regret the time spending on it

http://www.cnblogs.com/Thriving-Country/archive/2008/11/14/1333739.html

Tags: , , ,
Categories: .NET | Coding | ASP .NET

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen | Modified by Mooglegiant