News, examples, tips, ideas and plans.
Thoughts around ORM, .NET and SQL databases.

Friday, July 30, 2010

Recommended article: "The false myth of encapsulating data access in the DAL"

There is a great post by Ayende: "The false myth of encapsulating data access in the DAL". I'm posting the link to this article not just because I fully agree with its main thesis, but also because I know this is sitting in people's brain quite deeply.

I quite frequently get questions like "how can I design my DAL so that it will require nearly zero efforts to replace it?", or "how must I use DataObjects.Net that way?". And it's always quite difficult to make the people believe it's simply a bad idea, that will lead to exaggerated complexity and finally, waste of money.

Worse, our outsourcing department even have a customer, that put this requirement into SRS: "it should be easy to migrate from EF to any other DAL in that project". IMHO (sorry, Denis :) ), the only effect satisfying this requirement is noticeably more complex implementation in pretty simple project. Btw, EF was chosen for this project also mainly because of that requirement: EF is probably the less featured framework from any point except mapping. In the end of all we implemented this requirement, but got nearly 25% delay in delivery. Since I estimate the chance of migration to another ORM as something like 1%, this is nothing but just money waste at our side.

Speaking differently, all these people want to have ORM abstraction layer in their application. For ORM developer like me this sounds a bit ridiculous: ORM itself is designed to be an abstraction layer from the database, so finally these people want to develop an abstraction layer for another abstraction layer.

Why? The most frequent answer is: "I'd like to have an opportunity to switch to another ORM in future.". That's great, but it seems most of such people don't understand that complexity of developing such layer is comparable e.g. to complexity of such libraries as Qt. Do you agree GUI libraries are pretty similar? Initially it looks like true: there are windows, controls, etc., and most of them are nearly identical (scrollbars, buttons, ...). But anyone who knows all the details will say "it's hell, they're quite different!".

Of course, analogy between GUI and ORM tools may look strange: GUI tools are developing during 30+ years, but ORM tools started their way of wide adoption just 5...10 years ago. On the other hand, they're getting more and more complex. Compare what you can do now (LINQ) with ORM tools we have 5-7 years ago. This implies it will be harder and harder to develop ORM abstraction layer in future, because they'll evolve further nearly as GUIs and other well-known APIs.

So why people believe so much in ORM abstraction layer?

I feel this happens mainly because almost any book describing enterprise application design patterns makes a false statement in some form, and moreover, proves by relatively simple, and thus completely unrealistic example. Moreover, people tend to think even statement like "UI, BLL and DAL must be clearly separated" means "you must abstract your DAL from a particular ORM"!

And that's why, before thinking about developing your ORM abstraction layer, I strongly recommend you to:
  • Read this post by Ayende: "The false myth of encapsulating data access in the DAL"
  • Try to name at least one publicly recognized application having integrated ORM abstraction layer. To be honest, I don't know such applications. If you do, please name them in comments below this post.
So likely, you can't imagine my happiness :) Ayende is a very famous guy, so it's great he wrote about this problem. I really tired feeling myself fighting with this myth alone. Of course, I wasn't, but you know, it's hard to prove something while you don't rely on facts said by widely recognized people. And in this case my feeling was opposite: it was looking like nearly everyone recommends to design your application without binding to a particular ORM.

P.S. I also noticed a very good comment to that article: "Along the same line, you should not embrace a n-tier architecture when you can just build a 2-tier app. 2-tier can be a lot easier if you accept the limitations, and easier = time to market, cost, maintainability = money.". This fits quite well to our experience with our EF-based project I wrote about. It was designed as 3-tier application, although IMHO it was absolutely unnecessary in this case. So again, that's one more decision exaggerating the complexity and cost. So I feel I must be happy we got just 25% delay in this case :)

ORMeter (ORMBattle) scorecard is updated

Here is the announcement (there are some remarks about new results), and the new scorecard itself.

Wednesday, July 21, 2010

LINQ query translation optimization - one of real-life cases we've faced

Take a look at the issue 761.

It took about 2 hours to implement such transformation with SQL DOM - the changes Alexis Kochetov has made to resolve this issue are really tiny. It's difficult to imagine how ORM tools without SQL DOM-like model (e.g. NHibernate) can handle such cases. So our approach is quite solid from this point.

P.S. Tobias, thank you a lot for your analysis of this case!

// This post is actually written solely to advertise our support services and the team itself ;)

Tuesday, July 20, 2010

DataObjects.Net v4.3.0 installers are updated (build 5605)

We've fixed few more relatively important there - at least, for us:

1. Samples installation script was not properly executed by installer

The consequence: it was impossible to open any sample relying on IIS (ASP.NET sample, WCF sample) without manual hacks. Currently there is only one issue left: our installer currently isn't capable of creating "DO40-Tests" database and providing appropriate permissions for it, so you should do this manually (this is described in Manual).

Remember that to run IIS samples, you should grant dbowner permissions to account "ASP.NET 4.0" application pool is running from (or "DefaultAppPool" for .NET 3.5 version).

2. New WCF sample utilizing DisconnectedState

This sample was actually implemented few months ago; now it is officially available:


Its WCF service page:


WPF client using it:


Console client:


3. Finally, there is a set of important fixes and improvements

As usual, new builds are already in Downloads area.

Friday, July 16, 2010

DataObjects.Net v4.3 installers are updated to build 5521/5522

We resolved one more issue with License Manager there, so it's highly recommended to update to this version.

DataObjects.Net v4.3 installers are updated to build 5515

We've fixed a set of important issues there, including:
  • Issue 749: Installer must show build number
  • Issue 748: Shortcuts to Samples don't work
  • Issue 744: Shortcut to License Manager points to wrong path
  • Issue 737: Persistent field with name "State" is not supported
As you might assume, this update is highly recommended. New v4.3 installers (build 5515) are uploading to Downloads section now. The process will be finished in approximately 20 minutes.

Thursday, July 15, 2010

Check out the funny quest

Hey guys, wanna have some fun?


Check out the questions with “quest” tag on our new support website (beta).


Here are the recent ones:


support-quest


And there are much more! =)

Nice comment in our uninstall poll

Yesterday we've got funny, but very pleasant comment in our uninstall poll:

You absolutely need to clone Dmitri. :)
I think it's legal in Amsterdam. (Pretty much everything is legal there.)

I'm absolutely agree with the person that left it :)

P.S. This is an approval we read all the comments you leave to use there :)

New DataObjects.Net order pages

According to announced pricing model, the following DataObjects.Net editions and prices are valid from today:


Links to order pages:
Upgrade subscription prolongation:
  • For Professional and Ultimate Editions: order your primary license and necessary amount of hardware licenses with "DOUPGRADE2" coupon code (70% discount).
  • For Basic and Standard Editions: order your primary license and necessary amount of hardware licenses with "DOUPGRADE1" coupon code (60% discount).
Other remarks:
  • You should order one Primary License, and, optionally, any number of additional Hardware Licenses. Any Primary License already includes 3 prepaid Hardware Licenses in accordance with above table.
  • All the order pages are secure.
  • We provide 45-day money back guarantee.
  • If earlier you already purchased any of our products, enter ''CUSTOMER" coupon code at the order page to get 15% discount for your new license. The discount is provided for Professional and Ultimate Editions of product, as well as for its hardware licenses.
License page will be updated in accordance with this information shortly.

support.x-tensive.com goes beta

Hello everybody,

Today we are inviting all of you to take a look and try our new tech support service. We have done our best to provide better support service for you and to get rid of archaic and slow phpbb phorum with its inconvenient autonomous authentication system:
  • We were looking for a simple and fast StackOverflow-like Q&A system and finally we choose excellent OSQA engine.
  • We developed special migration process and heuristic tools in order to provide smooth and painless migration & transform all existing topics and messages from the old conversation-base domain model into the new Q&A-based one.
  • We implemented and configured the integrated user authentication with x-tensive.com website through OpenID protocol, so no additional registration steps are required.
What we haven't managed to do is to transfer the number of user posts into reputation (repo/kudo).

If you wish to help us make it better, please try it in action: take a look at already imported conversations, their formatting, check how OpenID works, etc. Any comments or suggestions are welcome! I suppose, it is better to post all your proposals, observations & bug reports concerning new support service straight there, so that we could test it in real life.

Important note:
As the website is still in beta, all its content might be removed/replaced anytime until it is officially opened, so please don’t create any real questions concerning DataObjects.Net or HelpServer products. For these topics current forum is still the best place to go.

Thanks!
Dmitri Maximov

Monday, July 12, 2010

DataObjects.Net v4.3 and v4.2.4 are available

We just released DataObjects.Net v4.3 final, as well as updated its GPL version to v4.2.4. Almost complete list of implemented issues can be found here.

DataObjects.Net v4.3 is the first fully commercial version in v4 branch, so if you're going to use this version, you'll need a license (but you still can use v4.2.X versions absolutely for free). Licenses of existing customers were converted to new license types according to the following rules:
  • Old Enterprise licenses were converted to new Ultimate licenses;
  • Any other old licenses were converted to new Professional licenses.
Note that now we bind a number of hardware licenses to each primary license, and this number is finite for Professional license. So if you need additional hardware licenses for your existing Professional license, please notify us - we will activate them for free, if the original license isn't expired yet.

This is the first time we switch from less to more restrictive licensing model, so there can be some issues. Please contact us, if:
  • You feel you must have (or need) another license type accordingly with your original purchase.
  • Expiration date of your subscription must be different.
  • You need additional hardware licenses.
  • You experience any issues with license activation.
  • You need to prolong your trial (this is possible - I'll make an additional post about this).
  • We didn't prolong or issue your free license. Most likely (e.g. if there is any work in progress, etc.) we'll prolong it for free. Please read this post, if you'd like to get a free license.
  • Your free license is about to expire, please contact us as well. Shortly we'll review the expiration dates of such licenses, so some of them might be fixed (e.g. there are people that must have lifetime licenses, but currently all the dates are automatically set to 2 year period at max).
  • You experience any issues related to PostSharp license check. We've got lots of questions related to PostSharp licensing, so I recommend you to read these threads for details: 1, 2 and 3.
  • There is anything else - important or unexpected.
Other notes:
  • Nightly builds for v4.3 will be available during this week.
  • There is a chance installers will be updated once more on this week - we'll try to fix all the issues related to licensing almost instantly, especially if they'll be blocking.
Fastest ways to contact us, if there is something urgent:
  • Skype to alexyakunin or dmitri.maximov
  • GTalk to alex.yakunin at GMail dot com
  • Call +7 922 222 7300
  • For regular inquiries, please write to info, sales or support@x-tensive.com.
P.S. Users from Russia and CIS countries, remember, there is still active (but almost expired) proposal for discounts.

Friday, July 09, 2010

We're switching to new licensing model

Starting from yesterday we're updating our software to support new DataObjects.Net licensing model. As one of the effect of this, order processing is delayed until the end of update. We're planning to complete all the jobs till 12:00 AM July 12, 2010.

Thursday, July 01, 2010

Local collections in Entity Framework: analyzing generated SQL

Alexey Gamzov just sent me an example showing how EF deals with large local collections.

Query:
from edge in session.GetAll<Edge>()
join nodeId in nodes on edge.ChildId equals nodeId
select edge.ParentId
nodes is local collection of 60+ GUIDs (IEnumerable<Guid>).

SQL:
SELECT
[Extent1].[ParentId] AS [ParentId]
FROM  [dbo].[Edges] AS [Extent1]
INNER JOIN  (SELECT
  [UnionAll66].[C1] AS [C1]
  FROM  (SELECT
    [UnionAll65].[C1] AS [C1]
    FROM  (SELECT
      [UnionAll64].[C1] AS [C1]
      FROM  (SELECT
        [UnionAll63].[C1] AS [C1]
        FROM  (SELECT
          [UnionAll62].[C1] AS [C1]
-- 60 more similar constructions
              FROM  (SELECT
                [UnionAll1].[C1] AS [C1]
                FROM  (SELECT
                  cast('5b029492-7aaf-4253-a347-a85eca6d08e0' as uniqueidentifier) AS [C1]
                  FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
                UNION ALL
                  SELECT
                  cast('bc83a784-87d8-45a0-b3f9-5a74be942ee1' as uniqueidentifier) AS [C1]
                  FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
              UNION ALL
                SELECT
                cast('ee7acdbb-73d4-4228-bcc6-b83dcc22d286' as uniqueidentifier) AS [C1]
                FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
-- 60 more similar constructions  
          UNION ALL  
            SELECT   
            cast('e6c729f2-fd19-43e1-9209-094d165cd551' as uniqueidentifier) AS [C1]  
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable63]) AS [UnionAll62]  
        UNION ALL  
          SELECT   
          cast('ed1c2991-75bc-4123-b524-ce9f9cee090a' as uniqueidentifier) AS [C1]  
          FROM  ( SELECT 1 AS X ) AS [SingleRowTable64]) AS [UnionAll63]  
      UNION ALL  
        SELECT   
        cast('0d5809e3-c841-4e1a-956d-ffca42446ac9' as uniqueidentifier) AS [C1]  
        FROM  ( SELECT 1 AS X ) AS [SingleRowTable65]) AS [UnionAll64]  
    UNION ALL  
      SELECT   
      cast('17574132-f67c-4622-aba9-abcde209a886' as uniqueidentifier) AS [C1]  
      FROM  ( SELECT 1 AS X ) AS [SingleRowTable66]) AS [UnionAll65]  
  UNION ALL  
    SELECT   
    cast('cbadcf79-0b51-4f96-8c95-b9576f31878c' as uniqueidentifier) AS [C1]  
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable67]) AS [UnionAll66]  
UNION ALL  
  SELECT   
  cast('55c50611-3745-47b3-af50-fdec7458b19d' as uniqueidentifier) AS [C1]  
  FROM  ( SELECT 1 AS X ) AS [SingleRowTable68]) AS [UnionAll67] ON [Extent1].[ChildId] = [UnionAll67].[C1]
Obviously, it fails - maximum subquery nesting level on SQL Server is 32. Luckily, it was possible to get rid of join in this case:

Query:
from edge in session.GetAll<Edge>()
where nodes.Contains(edge.ChildId)
select edge.ParentId
SQL:
SELECT 
[Extent1].[ParentId] AS [ParentId]
FROM [dbo].[Edges] AS [Extent1]
WHERE [Extent1].[ChildId] IN (
  cast('5b029492-7aaf-4253-a347-a85eca6d08e0' as uniqueidentifier),
-- About 60 more similar constructions
  cast('55c50611-3745-47b3-af50-fdec7458b19d' as uniqueidentifier)
)
It works ;) Although it's a bit strange they don't parameterize GUIDs here.