Starting with LLBLGenPro in your Project

LLBLGenPro is an object relational mapper which generates code for the data access layer from the database, in the coming releases it’s been planned to engineer from LLBL Project to create database. I am using v2.6 in my current project and happy with it so far. One of the strong points of v2.6 is it has good Linq support.

You can also look into other ORMs with Linq support including Entity framework (Microsoft), Linq to SQL (Microsoft) and Subsonic.  Entity framework is going through a major overhaul in version 4.0 and can also expect some improvements in Linq to SQL.  Subsonic is an open source project maintained by Rob Connery, the MVC-Storefront dude. 

And keep in mind that the following article uses LLBLGenPro Professional edition, and checkout their website for more on licensing, etc.

I have arranged the article into the following sections

  1. Project types: SelfServicing or Adapter paradigm
  2. Configure the Project using LLBLGenPro Editor
  3. Generate the Code using Adapter paradigm
  4. Your VS.Net Solution
  5. Writing your first test
  6. Debugging and catalog name overwrites
  7. Conclusion

 

1. Project types: SelfServicing or Adapter paradigm

You can create a SelfServicing or Adapter paradigm. In SelfServicing objects are lazy loaded from the database, and once loaded they don’t load again.  Adapter pattern doesn’t support lazy loading,  and you need to fetch all your objects and save them by yourself. Adapter is best suited if you are providing a service and you don’t expect your client to load them.  We will  generate project with Adapter paradigm in this write up.

 

2. Configure the Project using LLBLGenPro Editor

LLBLGenPro comes with an easy to use editor to generate the project from database. Open the LLBLGenPro editor from Programs and create a new project.  Provide your project information, choose the appropriate driver and select the catalog to work with.

 

image 

 

Once you create the project, you will notice your project explorer being updated with the Catalog, gives a skeleton for your entities, views and stored procedures. 

image

You can add entities by choosing ‘Add new entities mapped on tables from Catalog’ on the context menu when you right click on Entities which pops a modal box with the available tables to choose from.

image

 

I am interested in Product and it’s related tables, lets add them to the Project. Once you add to the project you can notice your Entities in Project Explorer being updated. And you can also change the Field Names to more meaningful.

 image

 

On the bottom if you notice the ‘Fields on relations’ tab, the editor has generated the table relations for you by looking at your database Primary/Foreign Key relationships.

The editor is not clever enough to pluralize the relationships, so change them  by editing the Field Name.

image

If you feel you need relations that are not provided in the database, you can create them easily using ‘Add new custom 1:1//1:n/m:1 relation’ on the ‘Relations’ tab

 image

Select the tables and fields on which you want to create the relations and you are good to go. 

From the Project menu select the Properties and customize the generated code.

image

I usually set the following properties to my needs:

  • CatalogRefresher:-
    Add NewElementsAfterRefresh: False (Don’t want to get new tables added automatically to my project)
  • Name construction:-
    EnforcePascalCasingAlways: False
    MakeElementNamePascalCasing: False
  • Output settings:-
    RootNamespace: AdventureWorks
  • Task performers:-
    FailCodeGenerationOnWriteError: True (If you use TFS, and the projects are not checked out, you need to enable this option)
  • CleanUpVsNetProjects: False

Have also changed the Project file suffix names to more meaningful as you can see under ‘Task performers’ in the above image.

 

3. Generate the Code using Adapter paradigm

Lets jump on and generate the code using Generate on the Project menu.

Make sure select the correct template group,  your target platform, language, and location.

image

 

4. Your VS.Net Solution

image

I have Adventureworks solution with 3 projects and lgp.

  • Generated projects
    • Adventureworks.DAL.Adapter
    • Adventureworks.DAL.Domain
  • Adventureworks.Tests:  Add the project reference to the above projects

For each of the Entities selected through the editor, a separate entity class is generated.  Since these classes are generated you don’t want to manually edit them,  the editor has template support to customize the code generation, and you can also partial classes to add additional behavior. 

 

5. Writing your first test

With the solution in place, we can write some test cases, finally :)

using System.Linq;
using AdventureWorks.DAL.Adapter;
using AdventureWorks.DAL.Linq;
using NUnit.Framework;
 
namespace Adventureworks.Tests
{
    [TestFixture]
    public class GetProductsTestFixture
    {
        [Test]
        public void GetAllProductsTest()
        {
            DataAccessAdapter adapter = new DataAccessAdapter();
            var linq = new LinqMetaData(adapter);
 
            var productQeury = (from p in linq.Product
                                select p);
 
            var product = productQeury.FirstOrDefault();
            Assert.AreNotEqual(product, null);
            Assert.AreNotEqual(product.ProductName,null);
        }
    }
}

And you can successfully run the test case.  My next question is how do I check the SQL generated?

 

6. Debugging and catalog name overwrites

Debugging:

It is a good practice to look at the SQL query generated to make sure you are getting your Linq statement correctly until you gain handle over it.  Even though Linq is part of the language, universal across objects, xml and database entities it doesn’t mean that the constructs supported in Linq to objects are supported in Linq to database. And after all each 3rd party linq provider has their own SQL query generation engine.

LLBLGenPro has support for various databases. For SQL Server and Oracle, you can check the SQL generated by adding the following diagnostics under system.diagnostics tab in your App.Config of the test project. Make sure you rebuild the projects for the changes to be copied to the output directory.

<?xml version="1.0"?>
<configuration>
 
    <system.diagnostics>
      <switches>
        <add name="SqlServerDQE" value="4" />
      </switches>
      
      <!--<switches>
        <add name="OracleDQE" value="4"/>
      </switches>-->
    </system.diagnostics> 
  
</configuration>

 

I am using Resharper plug-in for Visual Studio to run my rest cases, and you can see the query being generated. Nice :)

image

 

Catalog name overwrites:

Before delving into catalog name overwrites, lets me show you how to read the connection string for Adventureworks database using the App.config file

Step 1: Create a custom Adapter which reads the connection string from Configuration file.

Step 2: Add AdventureWorksAdapter.cs to the AdventureWorks.DAL.Adapter. 

image 

Step 3: Fill the AdventureWorksAdapter.cs

using System.Configuration;
 
namespace AdventureWorks.DAL.Adapter
{
    public class AdventureWorksAdapter : DataAccessAdapter
    {
        public AdventureWorksAdapter(string connectionString)
            : base(connectionString)
        {
          
        }
 
        public static AdventureWorksAdapter GetAdapter()
        {
            ConnectionStringSettings connection =
                new ConnectionStringSettings("Adventureworks", 
                    ConfigurationManager.AppSettings["Adventureworks.ConnectionString"]);
 
            return new AdventureWorksAdapter(connection.ConnectionString);
        }
    }
}
 

Step 4: Update the App.Config file

<?xml version="1.0"?>
<configuration>
    <appSettings>
        <add key="Adventureworks.ConnectionString" value="data source=.;initial catalog=AdventureWorks;integrated security=SSPI;persist security info=False;packet size=4096"/>
    </appSettings>
 
 

Step 5: Update the test method to use the AdventureWorksAdapter.cs

        [Test]
        public void Get_First_Product_Test()
        {
            //DataAccessAdapter adapter = new DataAccessAdapter();
            AdventureWorksAdapter adapter =AdventureWorksAdapter.GetAdapter();
            var linq = new LinqMetaData(adapter);
 
            var productQeury = (from p in linq.Product
                                select p);
 
            var product = productQeury.FirstOrDefault();
            Assert.AreNotEqual(product, null);
            Assert.AreNotEqual(product.ProductName,null);
        }

Now, lets run the test method, it successfully completes.  Lets not jump, we have a gotcha here.

If you change your connection string in the App.Config to reference another instance of Adventureworks database, lets call it Test Server, and run the test case. Open the SQL Server Profiler on your Test database, you will not notice any activity from your client.

LLBLGenPro caches the Connection string used to generate the project file, even though your App.Config is pointing to your Test Server.

To suppress the cached connection string you need to overwrite the catalog names.

 

Catalog Name Overwrites:

Step 6: Update your App.Config with catalog overwrites.

Open your App.Config in AdventureWorks.DAL.Adapter and check the name of your initial catalog

image

   image

Step 7: Overwrite the initial catalog.

Add config sections for sqlServerCatalogNameOverwrites and it’s values. I am also including commented Oracle catalog name overwrites

Find the complete App.Config below.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="sqlServerCatalogNameOverwrites" type="System.Configuration.NameValueSectionHandler" />
    <!--<section name="oracleSchemaNameOverwrites" type="System.Configuration.NameValueSectionHandler" />-->
  </configSections>
 
  <appSettings>
        <add key="Adventureworks.ConnectionString" value="data source=.;initial catalog=AdventureWorks;integrated security=SSPI;persist security info=False;packet size=4096"/>
    </appSettings>
  
    <system.diagnostics>
      <switches>
        <add name="SqlServerDQE" value="4" />
      </switches>
      
      <!--<switches>
        <add name="OracleDQE" value="4"/>
      </switches>-->
    </system.diagnostics>
 
  <sqlServerCatalogNameOverwrites>    
    <add key="AdventureWorks" value="" />
  </sqlServerCatalogNameOverwrites>
 
  <!--<oracleSchemaNameOverwrites>
    <add key="MySchema" value ="" />
  </oracleSchemaNameOverwrites>-->
  
</configuration>
 

Step 8:

Run the test case again and check the profiler on your Test database, and you will see the query.

 

7. Conclusion

This shall help you in getting started, starting from using the editor to generate the code –> writing your first test case.  In my next post I will cover how to write some complex Linq queries, prefetch data and using stored procedures.

 

Happy programming.

6 Comments

  • Thanks a lot for the great article about our work! :) Looking forward to the next one! :)

  • Btw: "The editor is not clever enough to pluralize the relationships, so change them by editing the Field Name."
    Yes it is, though you have to bind the plugin for that manually at the moment. Please see: http://www.llblgen.com/documentation/2.6/hh_goto.htm#Using%20the%20designer/designer_workingwithplugins.htm%23settinguppluralization

    The main reason for that is that it does english only, and some people might not want that (so can use their own plugin for pluralization). The current designer doesn't have a feature that it can bind plugins automatically unless configured manually, it's either automatically bound or manually bound (which are preserved). The names created for the various elements (like fields mapped onto relations) are created using patterns as well, in which you can specify if you want pluralization/singularization and which names you want to embed into the name (e.g. only the name of the related entity, do you want to suffix it with a suffix) etc.

    About catalog name overwriting: you don't need to grab the connection string from the config file, that's done automatically (so no need for the derived adapter class), and the catalog name to overwrite is in the mapping meta-data embedded in the generated code, not the one in the connection string. If you connect to the same server but specify a different initial catalog, you still get queries executed on adventureworks. This is because llblgen pro supports multiple catalogs per project, and therefore needs to have the catalog name embedded in the mapping meta data. To overwrite that name when a query is generated, you can specify which name to use instead or overwrite it with "" as you have done, which will make sqlserver pick the name specified in the connection string :)

  • Thank You Fran, nice to see your comments on my blog.

    I will explore about the plug-in for pluralizing the relation names and catalog name overwrites.

  • Frans,

    I dont think I understood you completly. Why is it that the connection strings are hard coded in the generated metadata. Shouldnt it be assumed that connection strings are defined in the config irrespective of howmany catlogues we have

  • I think you confuse "connection string" with "catalog name". Connection string is the string "database source=... ;initial catalog=...", catalog name is "Northwind". To be able to read the connection string from the application's config file, the connection string is stored under a key, normally Main.ConnectionString. This is configurable in the project properties.

    So what's hardcoded into the meta-data?
    - the catalog name + schema name of where a table/view is located (e.g. Northwind and 'dbo')
    - the key under which the connection string is stored under in the config file (though you can change that at runtime)

    So if you just want to specify a different connection string because you want to connect to a different server (e.g. the server dev01.mydomain.local instead of test.mydomain.local), you can just change the connection string in your config file.
    If you want to use the generated code on a different catalog than the one you used to create the project, you have to use catalog name overwriting. So if you created the project from the catalog 'DevCatalog' and you want to run it in production, which uses the catalog 'CustomerCatalog', you have to overwrite the name 'DevCatalog' with 'CustomerCatalog'. You do that by using catalog name overwriting.

    Now, you have to understand how sqlserver offers you access: the connection string allows you to connect to the database server. Then the server connects to the initial catalog you specified in the connection string. If a table reference in a query doesn't have a catalog name part in it (e.g it's just 'dbo.Customers'), it will look for that table in that initial catalog. However if it DOES have a catalog name present, it will simply look for the table in the catalog in the name. So if you specify as initial catalog 'Northwind', and you have a project created on adventureworks, you don't need catalog name overwriting, as 'adventureworks' is in the meta-data already.

    This is necessary because if you use two catalogs in your project, you have to specify their name with every table reference, as there is just 1 'initial catalog' in the connection string.

    I hope this makes things less confusing. In general: you should simply copy over the connection string from the generated app.config file to your own app's config file and it will work. If you need to connect to a different catalog: use catalog name overwriting. If you need to connect to a different server or use a different user: alter the connection string in the config file. :)

    Btw, your post wasn't posted on the ASP.NET main feed. If you add a tag which is one of the main feed tags (check weblogs.asp.net) it will be published on the main feed and you'll get more visitors ;).

  • Hmm, I made a long comment to answer you but it's not published... did you ever receive it?

Comments have been disabled for this content.