Friday, 05 September 2008
When writing our new messaging framework (GMX) for Genome v4, I ran into an interesting problem with LINQ. My colleague, Sztupi also ran into the same problem at almost the same time, so I thought it would make sense to write about it.

Before describing the problem, let me summarize some not-so-well-known facts about LINQ. If you are experienced with LINQ and the expression trees it uses, you can even skip this part and proceed from “So much for the LINQ overview” sentence to read about the problem I ran into.

When you write a query, such as

from c in customers
where c.City == "London"
select c
the C# compiler compiles it into a method call like this:

customers.Where(c => c.City == "London")

You can even write the Where() call directly as well; you don’t have to use the "from…" syntax. The parameter of the Where() call is a special construct called a lambda expression, which is something very similar to an anonymous method. In fact, sometimes it is an anonymous method.

Now the question is what you want to do with this lambda expression. If you want to filter customers that are already loaded into the memory, you want to have an anonymous method compiled from the lambda. However, if the customers reside in the database or in an XML file, you actually never want to evaluate the lambda as a .NET method call, but rather you want to transform it to SQL or XPath and let the underlying engine execute it. In this case, the anonymous method is not a good option, as it would be very hard to find out from the compiled CLR code that the method wanted to compare the City field to "London".

And here comes the big trick of LINQ. The C# compiler decides during compile time whether to compile the lambda expression to an anonymous method, or to an expression tree initialization code. If it compiles it to expression tree initialization, then during runtime, a new expression tree will be created whenever this Where() method is called, and this expression tree will represent the lambda expression you just described. O/RM engines like Genome can take this expression tree and transform it to SQL.

The only question remains is how the C# compiler can decide whether to compile the lambda to an anonymous method or to expression tree initialization. This decision is done by analyzing the parameter types of the Where() method you are actually about to call. If the Where() method takes a delegate as a parameter, it compiles to an anonymous method, and if it takes an Expression<T> parameter, it compiles to expression initialization.

It is good to know that the LambdaExpression class has a Compile() method, that can be used to compile the expression tree to a delegate. We don’t have a transformation in the other direction however, so you cannot get an expression tree from a delegate.

Genome | Linq
Friday, 05 September 2008 16:16:03 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, 05 August 2008

We frequently get asked about Genome’s future in the light of Microsoft’s upcoming .NET 3.5 SP1 release, which includes the Entity Framework and related technologies such as LINQ and ADO.NET Data Services (see also the beta release announcement on Scott Guthrie's blog giving a broad overview about the new features).

LINQ

LINQ (already released with .NET 3.5) provides query language capabilities for C# and VB.NET. Many new Microsoft technologies and products by other vendors rely on LINQ. It is crucial to integrate with it in order to stay connected with other technology trends. The distinction to LINQ2SQL needs to be emphasised, as many users confuse the two.
Genome has been fully integrated with LINQ since November 2007 (although we released several preview integration versions from 2006 on).  In fact, Genome was the first third party O/RM to provide LINQ integration. Developers who use Genome are thus not locked out of technology trends related to LINQ.

Astoria

Astoria is the code name for Microsoft ADO.NET data services. It provides a REST interface for any data source that supports the interfaces IQueryable (introduced with LINQ) and IUpdateable (introduced with Astoria). It is not an O/RM, but rather a messaging layer over O/RMs or other data sources.
Astoria’s current release focuses on integrating with Entity Framework, but it appears that its extensibility is still unstable when it comes to other frameworks. Astoria is a great concept, but we doubt anyone is currently using it in production.
We are confident that Genome will support Astoria in the near future (before the end of this year), when integration possibilities have matured and the integration issues on Astoria’s side have been resolved. As with LINQ, developers who use Genome are not hindered from using this technology.

Entity Framework (EF)

Entity Framework actually consists of three major modules:

  • Entity Data Model (EDM): this is an abstraction of a relational model that introduces higher level concepts such as inheritance, composition and associations. Any database ER model can be mapped to an EDM. It also provides a neutral (i.e. vendor-neutral) dialect of SQL. Developers can map their databases to EDM and formulate queries to them in eSQL. EDM exposes “entities”, which are not CLR classes but rather structured data rows with meta data attached.
  • Provider Model: this is an extensibility point of Entity Framework for database vendors, to allow them to adapt eSQL and the EDM (data types, etc.) to vendor-specific database models (vendor SQL and database type systems).
  • LINQ To Entities: this is an object-relational mapping tool that allows CLR class models to be mapped to an EDM. In other words, it maps CLR classes to EF entities.

Genome actually overlaps with LINQ To Entities to a certain degree. Entity Framework itself is much more than an O/RM, as it represents the next level of abstraction for data access on the .NET platform (hence its original name, ADO.vNext). If Entity Framework proves to be useful and is widely adapted by our target customers, we can imagine integrating Genome with Entity Framework by replacing LINQ to Entities and allowing CLR business models to be mapped to EDMs with Genome. This would help our customers benefit from the Genome O/RM API and utilise EDM for other applications such as reporting, etc.

Our main concerns about Entity Framework and Genome’s value proposition:

Technical Overkill

There is the potential that the proposed development model and abstraction required by Entity Framework is overkill for certain applications (e.g. there are three models and all mappings between them need to be managed).

Tools provided by Entity Framework heavily depend on visual designers integrated in Visual Studio to manage the various mapping models and generate code from the models. This is especially the case with large and complex projects that involve large and complex models – which is what Entity Frameworks seems to target. We strongly doubt that relying on visual designers to that extent is a good approach. For example, resolving a merge conflict in the model (as can easily occur in projects with large teams) is not possible with a graphical designer, thus forcing developers to edit models manually.

Version 1 issues

Of course any first version of a product will have some immaturity issues which people usually have to more or less work around. However, since Entity Framework provides a radical and very complex new concept for abstracting data access, the functional completeness of Version 1 is very low compared to what the concept itself covers. The danger of encountering issues that are difficult or impossible to resolve is quite high in Version 1. This can be a particular problem in large enterprise projects, which is of course what Entity Framework appears to target.

The bottom line

The funny thing is that while LINQ2SQL is too simple for many applications, Entity Framework seems to be far too complex for many of our cases.

We are going to continue polishing Genome into an O/RM that we think is sophisticated enough to serve complex enterprise projects while also remaining simple enough to not force over-engineering. We are just about release Genome V4. Working on O/RM for .NET since 2002 has given us quite a lot of confidence in our approach: we balance flexibility and simplicity. We ensure that our customers are not locked out of technology trends on the .NET platform, so we will continue to integrate Genome with new technology concepts introduced by Microsoft in this field. We hope that our position as the first 3rd party O/RM to integrate with LINQ has already proven our commitment to this strategy.

Tuesday, 05 August 2008 17:18:05 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, 20 May 2008

I hadn’t touched the topic of web service proxy generation for a long time, but in order to fine tune our new message contract generation framework for Genome, I had to check it out once more.

My concrete problem is very simple: I want to generate a proxy for a web service, but instead of generating some DTO types based on the wsdl, I would like to use my DTO classes that are already implemented (I know that the wsdl-generated ones are just fine, but mine are a little bit better).

The old solution was to let Visual Studio generate the proxy code, and remove the shared type from it. And hope that you don’t have to update it too often, because you will have to do this again. It seems that with the web service proxy there are no real improvements. Although wsdl.exe has some nice settings, like /sharetypes, you cannot invoke it from the “Add Web Reference” dialog. So you have to complicate the development workflow anyway. I wonder why MS did not implement a backdoor, by which I could provide additional wsdl.exe parameters…

The better news is that the WCF client generator can also generate clients for web services. And in the “Add Service Reference” dialog, you can even configure it to reuse types from existing assemblies, if they are referenced in the client project. Super! This is what I wanted. But it does not work :-( … At least not if the service is an ASMX web service (it seems to work fine for WCF services). It still generates my DTO classes.

I have played a lot with it. It seems that the problem is that it does not recognize the matching DTO class, because it is annotated with XML serializer attributes ([XmlType], etc.) and not with WCF attributes. Indeed, if I attribute the class with [DataContract] and [DataMember] attributes, it finds it! However, there is a checking mechanism in the client generator that can check whether the reused type matches the wsdl definition. And it is this that seems to fail, even if I apply exactly the same attributes as it would generate. I have looked around, and it seems that this checking mechanism might fail even for WCF classes.

This is a trap. There is a validation framework that provides false validation errors and cannot even be switched off. So I’m still exactly where I was 5 years ago: manually removing the generated types from reference.cs.

Posted by Gáspár

Genome | WCF
Tuesday, 20 May 2008 14:32:14 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, 05 February 2008

No, this article does not nag about some code I've seen that misuses new features. This is how I did it - on purpose.

I've always disliked the way I usually set up data in the database for testing: recreate the database, create the domain objects, setting all the necessary properties, commit the context. Take this code for example:

DataDomainSchema schema = DataDomainSchema.LoadFrom("SomeMappingFile");
schema.CreateDbSchema(connStr);

DataDomain dd = new DataDomain(schema, connStr);

using (Context.Push(ShortRunningTransactionContext.Create()))
{
  Customer tt = dd.New<Customer>();
  tt.Name = "TechTalk";

  RootProject tt_hk = dd.New<RootProject>();
  tt_hk.Name = "Housekeeping";

  ChildProject tt_hk_hol = dd.New<ChildProject>();
  tt_hk_hol.Name = "Holiday";
  tt_hk.ChildProjects.Add(tt_hk_hol);

  ChildProject tt_hk_ill = dd.New<ChildProject>();
  tt_hk_ill.Name = "Illness";

  tt_hk.ChildProjects.Add(tt_hk_ill);

  tt.RootProjects.Add(tt_hk);

  RootProject tt_g = dd.New<RootProject>();
  tt_g.Name = "Genome";

  ChildProject tt_g_dev = dd.New<ChildProject>();
  tt_g_dev.Name = "Development";
  tt_g.ChildProjects.Add(tt_g_dev);

  ChildProject tt_g_mnt = dd.New<ChildProject>();
  tt_g_mnt.Name = "Maintenance";
  tt_g.ChildProjects.Add(tt_g_mnt);
  tt.RootProjects.Add(tt_g);

  Context.CommitCurrent();
}

What I dislike in this is the 'setting all the necessary properties' part. Part of it is that it's hard to follow the hierarchy of the objects.

The other is that I'm lazy.

Even if I'm typing with considerable speed - and keep pressing ctrl+(alt)+space and let ReSharper do the rest - I still hate it for its repetitiousness. I always wanted to have something like ActiveRecord's Fixtures in Rails - but I never had the time to implement it. Yeah, typical excuse, and that's how we usually lose development time even in the short run, so I know I'll have do it the next time I need to create test data.

Sure, I could always create builder methods for every type to handle, passing in the property values and collections etc, but even creating those is yet another repetitious task. I always longed for some more 'elegant' write-once-use-everywhere kind of framework. So when I read this post, I thought, maybe I can get away with writing a simple, but usable enough, initializer helper extension. Here's the resulting initializing code:

...

using (Context.Push(ShortRunningTransactionContext.Create()))
{
  dd.Init<Customer>().As(
     Name => "TechTalk",
     RootProjects => new Project[] {
       dd.Init<RootProject>().As(
         Name => "Housekeeping", 
         ChildProjects => new Project[] {
           dd.Init<ChildProject>().As(Name => "Holiday"),
           dd.Init<ChildProject>().As(Name => "Illness")
         }),
       dd.Init<RootProject>().As(
         Name => "Genome", 
         ChildProjects => new Project[] {
           dd.Init<ChildProject>().As(Name => "Development"),
           dd.Init<ChildProject>().As(Name => "Maintenance")
         })
       });

  Context.CommitCurrent();
}

Prettier to the eye - but unfortunately, it's still not practical enough. For one thing, it’s easy to represent a tree this way, but it still doesn't offer a solution for many-to-many relations. That's a lesser concern though, and I have ideas for overcoming this (but haven’t done it so far due to lack of time, again). A greater problem is that it's not type safe: the parameter names of the lambdas (Name, RootProjects, ChildProjects) are just that - names, aliases; they are not checked during compile time. Even as a dynamic typed language advocate, I don't like too much dynamic behavior in statically type languages - that usually results in little gain if any, while losing their advantages, even 'developer-side' ones, like refactoring or intellisense support.

So, no conclusions there - I don't know which way I prefer yet. It seems that I really will have to go on and write some xml-file based initialization library (which will share some of the abovementioned problems of the non-static languages, of course, but renaming those properties in the config by hand which you just modified in the code at least feels a bit more normal).

Still, if you're interested, here's the extension for doing the job:

public static class DataDomainInitializerExtension

{
  public static DataDomainInitializer<T> Init<T>(
      this DataDomain dd, params object[] parameters)
  {
    return new DataDomainInitializer<T>(dd.New<T>(parameters));
  }
}

public class DataDomainInitializer<T>
{
  private readonly T target;
  public DataDomainInitializer(T obj)
  {
    this.target = obj;
  }

  public T As(params Expression<Func<string, object>>[] expressions)
  {
    foreach (Expression<Func<string, object>> expression in expressions)
    {
      object value = GetValue(expression.Body);
      string key = expression.Parameters[0].Name;

      PropertyInfo property = typeof(T).GetProperty(key, 
        BindingFlags.Instance
        |BindingFlags.Public
        |BindingFlags.NonPublic);

      Type collectionType = GetCollectionType(property.PropertyType);
      if (collectionType != null)
      {
        CopyCollection(property, collectionType, value);
      }
      else
      {
        property.SetValue(target, value, null);
      }
    }
    return target;
  }

  private void CopyCollection(
      PropertyInfo property, Type collectionType, object collection)
  {
    object targetProperty = property.GetValue(target, null);

    MethodInfo addMethod = collectionType.GetMethod("Add");
    foreach (object enumValue in (IEnumerable)collection)
    {
      addMethod.Invoke(targetProperty, 
                       new object[] { enumValue });
    }
  }

  private static Type GetCollectionType(Type type)
  {
    foreach (Type @interface in type.GetInterfaces())
      if (@interface.IsGenericType && 
          @interface.GetGenericTypeDefinition() 
            == typeof(ICollection<>))
          return @interface;

     return null;
  }

  private static object GetValue(Expression expression)
  {
     ConstantExpression constExpr = expression as ConstantExpression;
     if (constExpr != null)
       return constExpr.Value;
     return (Expression.Lambda<Func<object>>(expression).Compile())();
  }

}

Posted by Attila.

Genome | Linq
Tuesday, 05 February 2008 13:31:19 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, 22 January 2008

With Genome, you can map standard 1:n and n:m collections for foreign-key/association table database patterns out of the box by using Collection<T> and <OneToManyCollection/> or <ManyToManyCollection/>.

Compared to arbitrary relationships, which can also be mapped with Genome by using Set<T> and a query, Collection<T> offers the following additional functionality:

  • Elements can be explicitly added and removed from the collection.
  • The collection is fully loaded into memory and kept consistent with in-memory object graph modifications.
  • For n:m collections, Genome can fully hide the association class (mapping the database association table) from the domain model if required.

However, for n:m collections, where the association class is annotated with additional values (besides the foreign keys), the standard Collection<T> mapping does not fit.

To provide better support for those mapping scenarios, I have created a Dictionary-like implementation for annotated many-to-many associations, where we can build the functionality on the existing collection support.

Example

I will use a simple domain model to present the idea. Let’s say we have Departments and Employees in our domain. An employee can work in multiple departments, and a department can have more than one employee. This classic many-to-many association is annotated with a job description. The job description is encapsulated in a struct called Job.

So the logical view looks like this:

In the database, we represent this kind of association with an association class/table as follows:

The task is to implement the Department.Employees property, which represents the annotated n:m relation in a consistent way.

Representing an annotated n:m relationshop in the domain model

In my opinion the best representation for Department.Employees is an IDictionary<Employee, Job>. It is ideal because the employees must be unique within the collection, and the annotation data can be accessed if you additionally specify an Employee (index into the dictionary with that employee). Note that this representation is only possible if the annotation can be represented with a single typ; however, you can encapsulate the annotations with a struct or class to achieve this at any time. You can use the <EmbeddedStruct/> mapping feature to map this struct on the EmployedAs class.

Mapping the association table as a one-to-many collection

First we have to map the one-to-many collection (Department.EmployedAsCollection):

protected abstract Collection<EmployedAs> EmployedAsCollection { get; }

<Member name="EmployedAsCollection">
  <OneToManyCollection parentReference="Department"/>
</Member>

Wrapping the association table into an annotated association

We will wrap this collection with a dictionary implementation to represent the annotated association. I have created a helper class AnnotatedManyToManyDictionary that carries out all necessary transformations. This strongly typed helper needs 4 generic parameters, as you have to specify the association class (TAssoc=EmployedAs), the class owning the collection (TOwner=Department), the “other side” of the association (that is, the key in the dictionary, TKey=Employee) and the annotation that is the value in the dictionary (TValue=Job). Basically, you have to wrap the collection with this helper:

public IDictionary<Employee, Job> Employees
{
  get 
  { 
    return new AnnotatedManyToManyDictionary<EmployedAs, Department, Employee, Job>
      (this, EmployedAsCollection, EmployedAsDepartmentEmployeeJobAccessor.Instance);
  }
}

Helper strategy implementation for getting and setting the keys and values of an association item

The helper class manages the underlying one-to-many collection and the association items to provide the required behavior. As you probably noticed in the constructor call, it still needs a little bit of help. You have to pass a strategy that “knows” how to get and set the key and value properties of the association item. In the current example, the EmployedAsEmployeeJobAccessor strategy knows how to get and set the Employee and Job properties on an EmployedAs object. Currently you have to write this piece of code to make that work:

private class EmployedAsEmployeeJobAccessor : 
  IAnnotatedManyToManyDictionaryAssociationAccessor<EmployedAs, Employee, Job>
{
  public static readonly EmployedAsEmployeeJobAccessor Instance =
    new EmployedAsEmployeeJobAccessor();

  public Employee GetKey(EmployedAs assoc)
  {
    return assoc.Employee;
  }

  public void SetKey(EmployedAs assoc, Employee key)
  {
    assoc.Employee = key;
  }

  public Job GetValue(EmployedAs assoc)
  {
    return assoc.Job;
  }

  public void SetValue(EmployedAs assoc, Job value)
  {
    assoc.Job = value;
  }
}

Usage

Having done this, you can easily iterate through the employees in a department:

Department dep = GetSomeDepartment();
foreach(Employee e in dep.Employees.Key) { ... }

You can also iterate through the association elements to retrieve the associated employees of a department along with their job:

foreach(KeyValuePair<Employee,Job> in d1.Employees) { ... }

The job of an employee now depends on the associated department. The indexer of the employees collection takes an associated employee and looks up the job annotated to association:

Employee emp = GetSomeEmployee();
Job assignedJob = dep.Employees[emp];

Similarly, the job of an employee can be set for a specific department association:

dep.Employees[emp] = assignedJob;

Finally, when associating an employee to a department, the job annotation has to be specified as well:

dep.Employees.Add(emp, assignedJob);
Removing just requires the key, without the annotation:
dep.Employees.Remove(emp);

Limitations

The first limitation is performance with larger collections.. The current implementation uses a linear search for looking up the employee key in the collection, which can cause a performance hit in larger collections when adding or removing items or getting an item’s annotation (using the indexer). The reason for this is that I didn’t want to replace Genome’s internal representation of 1:n collections with a dictionary implementation.

The second limitation is that you need to manually code the helper strategy for getting and setting the annotation value in the association items.

Based on your feedback, we might implement this as a native mapping feature in an upcoming Genome release, thus resolving both limitations described.

Sample code

Please find the source code for the example described above attached to this article.

AnnotatedManyToManyAssociation.zip

Posted by TZ.

Tuesday, 22 January 2008 16:41:14 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Thursday, 15 November 2007
As I am writing this, I am just heading home from TechEd, waiting at the Barcelona airport for my return flight to Vienna. It has been a busy time for the Genome team since September - unfortunately so busy that we couldn’t take time to blog about all the things that are going on. We weren't at TechEd only as attendees, but also exhibiting in the Visual Studio Partner area, with a total of 8 TechTalkers in Barcelona. To catch up with all the things that have happened since September, I’ll start with TechEd, while the memories are still fresh.
Thursday, 15 November 2007 20:02:27 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, 08 November 2007
Typically, Genome is used to map tables to their data domain objects. But what to do when you have to use a database that is not made for mapping objects and therefore is not in any normalization form etc.?
Thursday, 08 November 2007 16:23:06 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Sunday, 16 September 2007

There are a lot of discussions how to properly mock an O/RM to achieve unit testing.

In this article, I will describe how an application implemented with Genome can be tested by means of unit testing. By stealing (and also modifying) the sample domain from Fowler, I’ll demonstrate this with a simple WebShop application. The use case that we are going to investigate is the ordering process itself.

The sample code used is provided for download at the end of the article. You need Genome 3.3 (beta 1) to execute the sample.

Sunday, 16 September 2007 15:25:25 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, 15 September 2007
TheServerSide.Net has just published our case study about DataReturn's experiences of using Genome to rebuild website for BMW USA. The site has quite critical performance requiremens of up to 1 million sessions per day.

Posted by Chris

Technorati Tags:

Saturday, 15 September 2007 10:19:10 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, 10 July 2007

Recently we received a question from a customer about how to express a sort criteria based on a condition. As the sort expression in Genome is nothing else than an implicit function (lambda) executed on the candidate element to return the value to sort by, this can be quite easily achieved.

As a simple example, let’s use the Northwind database again. A customer there has a Country and a Region property. Imagine you want to order all customers in the USA by Region and all the other customers by Country. Additionally you want to have USA customers first, then the others.

A Genome set can be sorted using the OrderBy() method. It takes an implicit function as a parameter, which is denoted using [] in OQL. The condition can be expressed using the ? operator, which is translated to a CASE WHEN in SQL. Hence, the order function can be expressed like this:

When the customer is located in the USA, then order by region; otherwise, order by country:

Country=="USA" ? Region : Country

To make sure customers located in the USA are listed first, I am prefixing the Region with a space (I know this is a hack, but it will do for this example). Hence, the final OQL looks like this:

extentof(Customer).OrderBy( [ Country == "USA" ? " " + Region : Country])

which translates to the following SQL:

SELECT … FROM Customers
  ORDER BY
    CASE WHEN (Country="USA")
       THEN (" " + Region)
       ELSE (Country)
    END ASC

Posted by Chris

Technorati Tags: ,

Genome | OQL
Tuesday, 10 July 2007 21:00:41 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, 04 July 2007
The Genome OQL Query Analyzer (QA) is a very helpful tool when you are developing with Genome: it allows you to load a mapped business layer to execute any kind of OQL queries. In this article, I demonstrate how the latest mapped business layer, along with its mapping, can be loaded by starting the Genome QA with a single click in Visual Studio’s solution explorer.
Genome | OQL
Wednesday, 04 July 2007 13:47:14 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, 29 June 2007

In my last post, I described how to use the Genome Web Application starter kit to rapidly create a web application that uses Genome.  To prove that Genome is not just for web applications, I will now show how to create a windows forms application with Genome.  There's no wizard that will create forms automatically (yet?), so there are a couple more manual steps.  As you will see, however, it's not too difficult.

I open visual studio, and reuse the datadomain and mapping projects I created in the first post in this series.  Then I add a new Windows Application project, call it WinForms and designate it as Start Project. I reference the datadomain and mapping projects, and the System.Configuration assembly.  I also reference the TechTalk.Genome assembly, which is located in C:\Program Files\TechTalk\Genome 3.2 Professional Edition for .NET 2.0\Bin\TechTalk.Genome.dll on my pc. I rename the Form1 files to MainForm. I add an App.config file, and paste the connection string from the web project that I created in my last post.  I then add a bindingsource to the form, and call it customersBindingSource.  I configure the bindingsource to use the Genome.DataDomain.Customer class from the DataDomain assembly (1). I add a DataGridView control to the form, dock it to fill the form, and have it use the customer bindingsource.  You can choose which columns you want to display in the grid; not all of them are that interesting to watch ;-)

So far, we used standard Windows Forms development techniques, but we still need to fill the datasource of our customer bindingsource.  This is where it gets more interesting.  We need a bit of plumbing code, but fortunately, we can use that most venerable of code reuse techniques: copy and paste.  I Open up the directory where Genome is installed (C:\Program Files\TechTalk\Genome 3.2 Professional Edition for .NET 2.0 on my pc).  I drill down to Samples -> CSharp -> QuickStart -> Step3-> WinFormsClient.  I Copy the files ContextBoundForm.cs, ContextFactory.cs  and Helper.cs to the directory of my WinForms project, and include them in the project.  I open the files and change the namespaces to WinForms. In Helper.cs, I change the name of the _schemaAssembly field to "01ReverseEngineering.Mapping" (which is the name of the mapping assembly compiled by the mappings project from my first blog post in this series.). I change the name of the connection string to "MyRole" (or whatever you defined as the name of the connection string in your app.config file). Now I open MainForm.cs in code view and make the class inherit from ContextBoundForm.

This code won't compile yet. The reason being that there's a using directive TechTalk.Genome.Extensions.Windows.Forms in ContextFactory.cs.  If you are familiar with the theory behind windows databinding, you will know that  the IBindingList interface is essential when binding lists of data to a datagrid or a listbox.  However, Genome's Set<T> (which is what is returned by any Genome query) does not implement that interface.  The Genome team provided a SetBindingList<T>, which is a wrapper around Set<T> that implements IBindingList.  You can find the code for this class in C:\Program Files\TechTalk\Genome 3.2 Professional Edition for .NET 2.0\Extensions\Windows.Forms\SetBindingList.cs. I add this file to the WinForms project (you can add it either as a copy or as a link). I compile to make sure that I have copied all code I need.

What is all this plumbing code about? One of the central concepts in Genome is the Context.  A idea of a Context in Genome is comparable to a connection to a database.  There can be many connections to the same database, but you need at least one connection in order to do something usefull on your database. The same is true for a Context.  The Genome equivalent of a database is called DataDomain, by the way.  ContextBoundForm inherits from System.Windows.Forms.Form and adds a propery and a couple of methods for using a Context.  ContextFactory does exactly what its name suggests.

Now at last we can populate the custerm binding source. I open MainForm.cs in design view, and double-click on the Form's title bar to create a handler for the load event. Thanks to all our plumbing code, I only need to write customersBindingSource.DataSource = new SetBindingList<Customer>(Helper.DB.Extent<Customer>(Context)); - after adding using directives for Genome.DataDomain and TechTalk.Genome.Extensions.Windows.Forms, that is.  I hit F5 to debug and run the application.  If all goes well, the main form loads and you will see the list of customers in the data grid.  In my case, not all went well at first and I had to make sure that my windows user account had appropriate permissions on the Northwind database.  The result looks something like this:

That's it for today.  This post turned out to be way longer than I anticipated, so I will save up the Orders and OrderDetails part and the editing part for the next post.

(1): If you have never worked with bindingsources in a windows forms application (and even if you have), I can highly recommend Brian Noyes's book Data Binding with Windows Forms 2.0 - Programming Smart Client Data Applications with .NET: it's full of information about working with data binding in Windows Forms, and is an enjoyable read.  If you are interested in the inner workings of data binding, be sure to check out chapter 7, Understanding Data-Binding Interfaces.

Posted by Dirk

Technorati Tags: object relational, getting started

Friday, 29 June 2007 10:59:29 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, 28 June 2007

Mats Helander, whom I have already had the pleasure to meet personally several times, wrote about an O/RM challenge in his blog.

While it is always fun to participate in challenges, I want to criticize the problem Mats describes first, before I show how you can solve it with Genome.

The challenge only concerns how efficiently an O/RM can read up a set of whole tables from the database. This does not make sense for two reasons:

  1. Usually, you don’t want to load up all the data from a database into memory (that’s one of the reasons why you use a database).
  2. If you have special cases, where you cache whole tables from a database (e.g. some lookup data), caching takes place very seldom (e.g. once a day) and thus the efficiency of loading up the data is not of such a big importance.

Mats expresses the challenge in such a way that he demands that the O/RM may not join the related objects when loading from the database to find out about their relationships. Instead, the O/RM should load up all objects at once, and “discover” the relations between the objects afterwards on its own (without using the JOIN from the database). This results in three SELECT statements (SELECT * FROM Customers; SELECT * FROM Orders; SELECT * FROM OrderLines).

An O/RM usually maintains only an identity map to cache object lookup queries. This helps object references mapped through foreign key fields in the database to be followed without extra database roundtrips (given that the related objects are already loaded into memory). This means that following an Order to its related Customer works in memory, if all data is loaded up. To discover the Orders belonging to the Customer, however, the O/RM needs to perform a lookup query.

Some O/RMs, including Genome, allow collections to be preloaded in order to avoid unnecessary roundtrips when traversing object graphs deeply. So you can tell the O/RM to preload all the Orders of the Customers retrieved, and to preload all the OrderLines of the Orders retrieved. In this case, the O/RM builds a map for relating the objects in memory while loading up the data.

Usually you only want to load up the related children of the parent table. It doesn’t make sense to load up all orders from the database only to fulfill the orders of three specific customers. To ensure this, an O/RM typically JOINs the related data to the filtered parent table.

Not filtering the parent table is a very special case. Introducing an optimisation for this case is possible, but would make no sense (for the initial reasoning above). Besides that, I wonder how large the loaded table has to be in order for that additional JOIN to make a significant difference, giving the whole performance optimisation sense at all. I guess in those cases, it is out of the question to cache the results in memory anyway, which is the premise of the scenario. Another drawback of this optimisation I want to point out is that it can turn out to be less efficient very quickly when the parent reference is nullable, as unnecessary data is loaded up again.

Still, this is a challenge and a lot of people interested in O/RM read it; so, let’s solve it with Genome.

Genome provides two infrastructures for retrieving and caching relations: collections and indexing.

The collection infrastructure provides rich support for handling specialised relation types such as 1:n and n:m relations. Usually, I would recommend using Genome’s collection mapping feature to support Mats’ scenario, except that Genome uses a JOIN to limit the related objects loaded up from the database.

Indexing is a Genome infrastructure that automatically detects even complex relationships, based on the loaded data. It is more complex to configure, use and maintain, but it can support Mats’ exotic scenario. Having mapped the business layer with Genome, the following three lines of code will do the trick:

using (Context.Push(LocalContext.Create()))
{
    IndexManager.FillIndex(Context.Current, dd.Extent<OrderDetail>(), 
                           IndexManager.GetIndex(dd.Schema, typeof(OrderDetail), "IdxOrder"));

    IndexManager.FillIndex(Context.Current, dd.Extent<Order>(),
                           IndexManager.GetIndex(dd.Schema, typeof(Order), "IdxCustomer"));

    Set<Customer> customers = dd.Extent<Customer>().ToArray();

   Dump(customers);

}

Inside the using block, the first two lines of code load up all OrderDetails and all Orders. Additionally, they saturate the indexes for the relationships Order->OrderDetail and Customer->Order. The third line of code loads up all customers. When Dump(customers) traverses through the object graph, all relationships are served from memory.

Note that this feature is not limited to simple 1:n and n:m relationships. It works for more complex relationships as well, such as retrieving pending orders of a customer etc.

Posted by Chris

Technorati Tags: object relational, challenge

Thursday, 28 June 2007 15:17:52 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, 26 June 2007

In Genome, you can use ToObject() to return a single object from a query that has zero or one result element. The Genome documentation gives the following explanation about the restriction on the number of result elements:

The method should not be called for sets that may contain more than one element. Calling the method for these kinds of sets results in different behaviours based on the database platform and the calling context. If you need to retrieve the first element of a set, the combination of Set.GetRange and Set.ToObject has to be used, as in the following example.

But when can you be sure that a query returns only zero or one element? And what happens if you do not follow that advice?

A common case that would require using ToObject() is when you need to map an inverse object reference of a 1:1 relationship in the domain model.

Imagine the following example, where a company car can be assigned to one or no employee: In this case, the company car has an object reference to the employee it can be assigned to, represented by a foreign key in the database. Vice-versa, the employee has an object reference to the assigned company car, implemented through a lookup query that returns the car that is being assigned to this employee:

public abstract class CompanyCar
{
	...
	public abstract Employee AssignedTo { get; set; }
	...
}

<Type name="CompanyCar">
	...
	<Member name="AssignedTo"><NearObjectReference/></Member>
</Type>

public abstract class Employee
{
	...
	public abstract CompanyCar AssignedCar { get; }
	...
}

<Type name="Employee">
	...
	<Member name="AssignedCar" Oql="extentof(CompanyCar)[ccar: ccar.AssignedTo==this].ToObject()" />
	...
</Type>

Note the following details:

  1. Employee.AssignedCar is readonly, while CompanyCar.AssignedTo is read/writeable. This is logical, since Employee.AssignedCar is only mapped to a query, where you cannot “set” the result. Of course, you can implement a more sophisticated property on Employee which would allow the car to be set directly for an employee, but I leave this out for simplicity’s sake.
  2. The lookup query mapped to Employee.AssignedCar retrieves a single car instance by using ToObject(). This assumes that the lookup query returns only zero or one result element, which is the point I wanted to discuss in this article.

Having mapped this, you can freely navigate from CompanyCar to Employee and vice-versa, as shown below.

Navigating from CompanyCar to Employee executes a lookup query for the foreign key against the database:

SELECT ... FROM Employee WHERE Id = {CompanyCar.AssignedTo}

Navigating from Employee to CompanyCar executes a lookup query for the primary key of the Employee instance in the AssignedTo fields of the CompanyCar table:

SELECT TOP 1 ... FROM CompanyCar WHERE AssignedTo = {Employee.Id}

The beauty of this mapping is that the domain model’s user does not need to be aware in which direction the relationship is mapped in the database. You can even build more complex queries using the property . For example, finding all Employees that have a CompanyCar assigned to them is easy in OQL:

extentof(Employee)[AssignedCar != null]

This translates to the following SQL:

SELECT ... FROM Employee
  LEFT OUTER JOIN CompanyCar ON CompanyCar.AssignedToId=Employee.Id
  WHERE NOT CompanyCar.Id IS NULL

If you change the database schema to point the foreign key in the other direction, the same OQL is translated to the following SQL:

SELECT ... FROM Employee WHERE NOT AssignedCar.Id IS NULL

The important point that I want to make is that ToObject() works fine as long as you can be sure it will return only zero or one result. In my example, if there were more than one car assigned to an employee, then the SQL query would return duplicate employee entries for those employees with more than one car assigned:

SELECT ... FROM Employee 
  LEFT OUTER JOIN CompanyCar ON CompanyCar.AssignedToId=Employee.Id
  WHERE NOT CompanyCar.Id IS NULL

A wrong approach to fixing this problem is to use a distinct projection, eliminating the duplicate employee entries from the result:

 [this distinct]extentof(Employee)[AssignedCar != null]

This translates to:

SELECT DISTINCT ... FROM Employee 
  LEFT OUTER JOIN CompanyCar ON CompanyCar.AssignedToId=Employee.Id
  WHERE NOT CompanyCar.Id IS NULL

There are several reasons why using a distinct projection is not a good solution to the problem in this case. First of all, you do not want to change the semantics of your query in OQL, just to work around this problem. There might be many other places where you run into similar problems which you would have to fix with additional projections or other hacks one by one. Second, DISTINCT limits the query in some cases, e.g. you cannot sort by a field not contained in the selector anymore when using DISTINCT.

The right approach to solving this problem reflects the fact that there can be more than one CompanyCar assigned to an employee in the mapping of the relationship. There are two ways of doing this.

The simplest is to tell Genome to expect more than one result in the lookup, and return only the first. This can make sense if you want to return “any” of the assigned cars. If you combine it with an order criterion that defines which cars to return first, this can be even more meaningful. The following mapping would return the most expensive car assigned to an employee:

<Type name="Employee">
	...
	<Member name="AssignedCar" Oql="extentof(CompanyCar)[ccar: ccar.AssignedTo==this].OrderBy([Price descending]).GetRange(0,1).ToObject()" />
	...
</Type>

.OrderBy([Price descending]) ensures that the most expensive car is returned first.

GetRange(0,1) tells Genome to make sure only one result is returned. Depending on how AssignedCar is used in another OQL, Genome shapes the resulting query accordingly.

After mapping AssignedCar as above, the original query

extentof(Employee)[AssignedCar != null]

is now translated to the following SQL:

SELECT ... FROM Employee
  WHERE NOT(
    SELECT TOP 1 FROM CompanyCar WHERE CompanyCar.AssignedToId = Employee.Id
    ORDER BY CompanyCar.Price DESC
  ) IS NULL

Note that, because GetRange(0,1) is used in the mapping of Employee.AssignedCar, Genome implements the same OQL to search for employees without a car, using a sub-query instead of using LEFT OUTER JOIN.

Depending on your business use case, you might choose to do more complex refactoring of your business model to reflect that more than one car can be assigned to an employee. For example, you could introduce an additional property to Employee that returns Set with all assigned cars. You would still need to define how queries that retrieve only a single instance of a car should work, no matter how many cars are assigned to an employee.

Summary

When using ToObject() alone to retrieve a single element from a set, make sure that the set can only contain zero or one element. Otherwise, you will end up with unwanted side effects when building more complex queries based on this query.

When you know a query can return more than one element, but you just want to fetch the top element, use GetRange(0,1) in combination with ToObject(). For example, if you want to retrieve the most expensive car from the car pool, use

extentof(CompanyCar).OrderBy([Price descending]).GetRange(0,1).ToObject()

It is also possible that your data is inconsistent; more than one CompanyCar may be assigned to an Employee, although business rules forbid this. In this case, this is a bug in your software which you should resolve otherwise (e.g. through proper business rule checks or database constraints). Using GetRange(0,1) does not really help, as it does not represent the business intent you want to implement.

It may also be tempting to use GetRange(0,1) “just to be sure”, but note that this adds unnecessary performance overhead. For example, joining in a TOP query is far more complex and slow than joining in the same without GetRange(0,1). In fact, this is the reason why we have not included GetRange(0,1) in ToObject().

Posted by Chris

Technorati Tags: object relational, getting started

Genome | OQL
Tuesday, 26 June 2007 10:46:19 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, 15 June 2007

Most software projects start with an existing database.  It's not often that you get the chance to start from scratch and design the database the way you like it.  Now, creating Genome mappings for an existing database is a tedious job, but thankfully we have the Database Reverse Engineering Wizard for that.  So let's start Visual Studio 2005, and create a new Database Reverse Engineering project.

Genome will start a wizard.  Connect to Northwind, select all tables, accept the names for the projects or choose your own, change any options if you like (I opted to have Genome create default constructors) and click finish.  Genome will now generate two projects for you, one with classes for your domain model, and one for the mappings of those classes to database tables.

Let's have a look at some of the class file that the wizard generated for you. Open the Order.cs (or Order.vb if you selected VB.NET as your language of choice).

    1 using System;

    2 using TechTalk.Genome;

    3 using TechTalk.Genome.Mapping;

    4 using System.ComponentModel;

    5 

    6 namespace Genome.DataDomain

    7 {

    8     [TypeConverter(typeof(ExpandableObjectConverter))]

    9     public abstract class Order : Persistent

   10     {

   11         #region Primary Keys

   12 

   13         public abstract int OrderId { get; }

   14 

   15         protected Order()

   16         {

   17         }

   18 

   19         #endregion

   20 

   21         #region Scalar Fields

   22 

   23         public abstract Nullable<DateTime> OrderDate { get; set; }

   24         public abstract Nullable<DateTime> RequiredDate { get; set; }

   25         public abstract Nullable<DateTime> ShippedDate { get; set; }

   26         public abstract Nullable<decimal> Freight { get; set; }

   27         public abstract string ShipName { get; set; }

   28         public abstract string ShipAddress { get; set; }

   29         public abstract string ShipCity { get; set; }

   30         public abstract string ShipRegion { get; set; }

   31         public abstract string ShipPostalCode { get; set; }

   32         public abstract string ShipCountry { get; set; }

   33 

   34         #endregion

   35 

   36         #region Reference Fields

   37 

   38         public abstract Customer Customer { get; set; }

   39         public abstract Employee Employee { get; set; }

   40         public abstract Shipper ShipVia { get; set; }

   41 

   42         #endregion

   43 

   44         #region One To Many Associations

   45 

   46         public abstract Collection<OrderDetail> OrderDetails

   47         {

   48             get;

   49         }

   50 

   51         #endregion

   52 

   53         #region Many To Many Associations

   54 

   55         public abstract Collection<Product> Products

   56         {

   57             get;

   58         }

   59 

   60         #endregion

   61     }

   62 }

The file starts out with a couple of using declaration that refence the Genome namespaces. The Order class is annotated with the TypeConverter attribute, which is useful to display Genome objects in a property grid.  The first member we encounter is a property for the primary key of the Order entity, in this case a simple integer.  There's also the default constructor, which is protected because we are dealing with an abstract class. Then come a number of simple properties, nothing exciting.  After that it gets more interesting.

The Orders table has several foreign key contraints.  Those foreign keys are represented by references to related objects.  For example, the foreign key to the Employees table as mapped by a property of type Employee.  We have the other direction as well: the OrderDetails table has a foreign key to the Orders table.  This results in the Order class having a collection of OrderDetail objects.  If you take a look at the OrderDetail class, you will find it has a property of type Order for its side of the relation.

Lastly we have an m-p relation between the Orders and the Products tables, with the OrderDetails table as connection table.  Genome creates a collection of Product objects in the Order class, and a collection of Order object in the Product class.

By this time, you are probably wondering why the classes and all those properties are abstract. The reason becomes clear when we use Reflector to have a look at the assembly compiled by Genome.

For every class generated by the Database Reverse Engineering wizard, there are two classes in this assembly: one in a namespace starting with GenomeContextBoundProxy and one in a namespace starting with GenomeContextUnboundProxy.  The Genome runtime will use one or the other depending on the Genome Context. The distinction between the two kinds of proxies isn't that important, though. What is important is the fact that Genome uses the proxy design pattern. This all happens behind the scenes however, so as an application developer you will only deal directly with the abstract classes.

In the next installment, I'll use the Genome starter kit to create a web application that uses the two projects we just generated.

Posted by Dirk

Technorati Tags: object relational, getting started

Friday, 15 June 2007 11:16:50 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, 15 March 2007

George Lawton contacted me at the end of February to ask some questions about O/RM as he was working on a story for theserverside.net. The story has now been published, and I think George Lawton and Jack Vaughn did a good job of providing an accurate analysis of the current situation of the O/RM market for .NET.

When I received George’s email, I was quite surprised that he was inquiring about the situation that people allegedly complain about O/RMs generating quick wins in the beginning that you pay dearly for at a later stage. In his article, you can read how strongly I disagree with this myth and I was pleased to see that other people quoted in his article feel the same.

George asked us the following three questions, which I found very interesting to discuss:

  • What specific features of Genome make it simpler to use, both initially and over time, than other O/RM tools?
  • What have been some of the major challenges in the use of O/RM tools, and what are the ways you have gone about addressing these?
  • What specific tips do you have to offer developers in getting the most out of using O/RM tools as part of the software development process?

Intrigued by his questions, I put together quite extensive replies – replies that may be of interest to others, too. Based on my answers to George, I have put together this article to outline our thoughts on the issues above and give some advice to developers who are evaluating O/RMs.

Thursday, 15 March 2007 15:59:23 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, 12 March 2007
Let’s be honest about it: getting to know Genome is a non-trivial undertaking. It may seem downright daunting. I want to share with you some of the things I did, hoping that someone might benefit from my experiences.
Monday, 12 March 2007 12:02:26 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, 26 February 2007

In my previous post I was discussing about how to mock test data for persistent objects mapped with Genome. Now I want to discuss how to provide this sample data in Blend so the designer building a front end with WPF actually sees how the UI would look like with data.

Genome | WPF
Monday, 26 February 2007 15:29:32 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, 24 February 2007

We’ve been working on a little research project recently with WPF and created a small (and hopefully handy) application where you can list your contacts synchronized from Microsoft CRM. We store the offline data in a SQL 2005 Compact Edition database and we access the data using Genome.

To make the experiment more exciting we involved a designer in the project, not only to design a cool UI using the features of WPF, but mainly to see how the collaboration between designer and developer works in reality.

Genome | WPF
Saturday, 24 February 2007 15:15:35 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, 20 February 2007

Yesterday we were releasing Genome 3.1. After making quite a big step from Genome 2.6 to 3.0 last November, I thought the 3.1 release would allow us to take a breath, do some polishing on the code and finish some of the stuff that just didn’t make it into 3.0.

How wrong I was.

The length of the What’s New for Genome 3.1 will easily tell you that this is not a minor upgrade. Some major improvements have been put into this release, so it is definitely worth upgrading to as soon as possible to 3.1 for everyone working with Genome.

Tuesday, 20 February 2007 17:03:07 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, 29 January 2007

I started working at TechTalk two weeks ago and one of my first tasks was – naturally – to get to know Genome. So I browsed through the tutorials and the quickstarts, and I watched the videos. Those gave me a general understanding of how to work with Genome. To get a real feel for it, I converted the data access layer of one of my pet projects to Genome. I know this pet project inside out, and it contains a couple of queries that are a bit more complex than your basis quickstart query. I felt that this was a good way to learn the details of Genome: take a project with a classic DAL that I know very well, and convert it to Genome while keeping all other aspects of the project. I struggled at first, but after a couple of days I came to grips with Genome and its query language and after that it went like a breeze.

What I like most about Genome is Query Decomposition. Suppose we have a Document entity and a Category entity. A Document can be assigned ("tagged") multiple categories, and there are many documents in each category - a classic m:p relation. In the dark ages of manual sql code, I'd have to write a stored procedure that gets all documents from the last 30 days. I'd have to write another stored procedure to get all documents in a certain category from the past 6 months. Thanks to genome, I have two select methods on my Document class for these scenarios. The first gets a set of documents from a specific time interval. The second gets a set of documents from a specific time interval that belong to a specific category. Using query composition, I can refactor these methods so that the second method calls the first method and does some more filtering on the result of the first method. Each idea is expressed only once in code. Genome takes care of executing just a single sql statement, even though I'm really calling two methods in my programming code. This is imo the real killer feature of Genome.

Posted by Dirk.

Monday, 29 January 2007 14:00:59 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, 05 January 2007

In the recent months there has been a lot of confusion in the community about what LINQ is and what it is not. If you discuss this topic with others and read through the blogs you will find a lot of different perspectives and opinions on LINQ.

Most of the questions and misconceptions about LINQ I have encountered are about mixing up LINQ with an O/RM system and not understanding the impact of LINQ to .NET based O/RMs.

This is a brief summary about LINQ and how it relates to O/RMs, using Genome as a concrete example.

Genome | Linq
Friday, 05 January 2007 18:55:23 (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, 31 May 2006

When I first saw Matt's blog entry, I thought this guy has gone crazy. They have just released the new CTP of LINQ, which should have been a source of great stress for him, whatever. He has gone crazy for sure. Shit happens.

Unfortunately I’m not the kind who writes yippees and hurrahs, but believe me, now I feel exactly the same as Matt - whoopee! And I also know the ticket to getting into this state: LINQ.

I have to keep my text short (huhuuu), so just look at this:

Wednesday, 31 May 2006 18:40:43 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [5]  | 
 Friday, 14 April 2006

On April 12th I presented Genome at Persistence Day in Karlsruhe, Germany which was organised by dotnetpro, a German .NET development publication. Persistence Day is quite interesting, as it is a full day event concentrating solely on two topics:

  • Object-relational mapping for .NET
  • Object-oriented databases for .NET

While the latter is more of a niche in today’s enterprise development market (still, quite an interesting one), there is a huge demand for object-relational access for the .NET platform. The event hosted nearly 200 people and was booked out quickly. The fact that a one-day event with a 99€ price tag that attracts only a regional audience (no one would travel further than a few hundred kilometres for it) was so rapidly booked out (and would have been so even if the event had been planned for 500 people, according to the organiser) amply demonstrates that the .NET developer community is starving for solutions to this problem.

Still, O/RM is an exotic thing on the .NET platform, while it is widely accepted in the Java world. When I attended a software architect workshop in Cortina this February with a group of Java and .NET architects, the Java people just yawned when O/RM topics were proposed for discussion. So how can it be that this topic is widespread on other development platforms but so underdeveloped in .NET?

I see two main reasons for that:

First of all, Microsoft contributes a lot to this situation. They announced Object Spaces twice (PDC 2001, PDC 2003) but never released it. Except at PDC (and on some rare occasions at TechEd), you will never hear about O/RM from Microsoft. It's very funny to read through Microsoft’s current Patterns & Practices chapter on “Designing Data Tier Components and Passing Data Through Tiers” without encountering the word “object-relational mapping” once. I understand that Microsoft does not endorse any specific products, but concealing an entire product category shows Microsoft's attitude to this topic quite well.

Another reason is the .NET development community itself. With few exceptions, many people are advocating against the use of O/RM. They already spoke against it some years ago and they still do. I don’t want to dispute their arguments here, but looking at the number of comments those people receive on their O/RM related posts clearly tells me what an important topic O/RM is for the .NET community after all.

Posted by Chris

Friday, 14 April 2006 15:34:02 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [2]  | 
 Thursday, 13 April 2006

I like the WinForms user interface, but not the Web UI. I know, I'm not alone with this, but please keep in mind that it's 2006 and you can conjure a full realistic 3D world on your PC with any of the trendy FPS games, but you go back to work the next day and have to work with an enterprise application with a web front end and still have to struggle with inconveniences determined by the technology you use. It's crazy, isn't it?

On the other hand (if I don’t count AJAX technologies, which are a big hope for me), you have the WinForms UI, which provides you with a useable environment for your applications. As we have mostly worked with web applications in the last two years, we looked into the ASP.NET improvements first when the new .NET framework came out. Although we found strange things there, what I have seen and tried out is really promising (I promise I'll collect our findings on this topic as well). Thus, full of enthusiasm (and knowing that many of our customers are interested in using Genome with WinForms UI), I’ve started to put together a sample that shows a few databinding scenarios using the ever famous Northwind database and Genome of course (the sample will already be online by the time you read this).

I'm a bit disappointed. I see the improvements and the fancy new stuff they have shovelled together at MS, but it cannot make me happy. Let me tell you what I've found.

Thursday, 13 April 2006 16:13:45 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [4]  | 
 Monday, 10 April 2006

We have just released a new version (2.5) of our O/R mapping tool, Genome. You may already have noticed that TechTalk frequently releases new versions of Genome. When we created the first automated data access layer implementation for one of our .NET projects four years ago (which later became Genome), we tried to build up a core framework that can be easily extended in many ways without breaking the existing public API. This allows us to provide frequent updates with improved functionality that can be used easily by our customers without spending valuable efforts on integration.

Genome 2.5 is a bit different. You might not notice any difference because this release is as backwards compatible as previous ones: when you upgrade, you most probably don’t have to do anything else but modify your references to Genome to use the new version. However, Genome 2.5 introduces a big change, or at least a bigger one than usual: we have integrated support for Oracle and Microsoft database server platforms into one build. This will also allow us to extend Genome’s support for further database platforms in the future more easily and it has made Genome, our lovely child (as we’re used to calling it), a teenager who has successfully graduated from elementary school.

You’ll probably say: “What’s the big deal? There are several O/RM products on the market that support multiple database platforms.” Well, that’s true, but there can be significant differences in how they support a specific database platform. The challenge is not to provide an abstraction for the various SQL syntax flavours used by different database platforms but to deal with the semantic differences found in those platforms, such as identity generation (automatically incremented field value versus sequence), limiting the result set to a maximum row count (TOP n vs. ROWNUM <=n), handling LOB parameters in grouped database commands or different database type systems.

In Genome 2.5 we have tried to provide transparent integration with the different database providers. And in most cases, it just works! You simply change the database provider setting in the properties of your DataDomain schema project, modify the connection string, and your application is ready to run on a different database platform. We have found, however, that providing a safe, straightforward and transparent solution is not always possible. Because of the semantic differences mentioned before, there are cases when you cannot achieve exactly the same functionality on another database platform. One problem is that of the empty string, to finally arrive at the topic I wanted to talk about.

Monday, 10 April 2006 18:44:21 (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  |