Register       Login  
   Small text Medium text Large text
  Useful links  
   
         
     
  Announcements  
 
Genome v4.2 SP10 released - Wednesday, May 18, 2016
Genome v4.2.11 provides fixes for the integration to Microsoft Visual Studio 2015. With the update DataDomain schema projects can be compiled to .NET 4.6.1 and .NET 4.6.2 as well. The service pack contains a few minor fixes in the Sqlite provider and in the runtime too.  
Genome v4.2 SP9 released - Tuesday, September 22, 2015
Genome v4.2.10 provides integration to Microsoft Visual Studio 2015 with the same functionality as for VS2013. Also with this update the DataDomain schema projects can be compiled to .NET 4.5.2 and .NET 4.6 too. The service pack adds support for PostgreSql database and contains a few minor fixes in the runtime too.  
Genome 4.2 SP8 supports VS2013 and .NET 4.5 - Thursday, October 24, 2013
Genome v4.2.9 provides integration to Microsoft Visual Studio 2013 with the same functionality as for VS2010 and VS2012. Also with this update the DataDomain schema projects can be compiled to .NET 4.5 and .NET 4.5.1 too. The service pack contains a few minor fixes in the runtime too.  
Genome 4.2 SP7 released - Wednesday, May 01, 2013
With a few fixes and a small feature!  
Genome 4.2 SP6 supports VS2012 RTM - Friday, August 24, 2012
Genome v4.2.7 provides integration to Microsoft Visual Studio 2012 RTM with the same functionality as for VS2010. This release contains only this tool enhancement and no change in the runtime.  
Genome 4.2 SP5 with VS2012 RC support - Friday, June 29, 2012
Genome v4.2.6 provides integration to Microsoft Visual Studio 2012 RC with the same functionality as for VS2010. This release contains only this tool enhancement and no change in the runtime.

Important note: Visual Studio 2012 RC comes with a change in the MsBuild system, that causes the Genome builds fail (in VS2012 and also in VS2010) with the following error:
error MSB4185: The function "CurrentUICulture" on type "System.Globalization.CultureInfo" has not been enabled for execution.

This problem will be fixed my Microsoft in VS2012 RTM. In the meanwhile you have to set the environment variable “MSBUILDENABLEALLPROPERTYFUNCTIONS” to “1”. (You might need to restart Visual Studio).
 

Genome 4.2 SP2 (v4.2.3) released - Oct 29, 2010
With many fixes and small features!   read more...
Genome 4.2 released - Feb 10, 2010
Supports now Visual Studio 2010!   read more...
Updated roadmap - Dec 22, 2009
learn more about the upcoming Genome v4.2 release   read more...
Genome 4.1 released - Mar 31, 2009
Read more about what's new in this release.   read more...
New Product Video released - Jan 16, 2009
Get a quick overview of Genome v4.   read more...
 
         
     
  Encapsulating and Reusing Queries  
 

Genome allows you to encapsulate and reuse the query logic of your business layer in the domain model without paying a performance penalty. Aside from all the nitpicking you can do when comparing different O/RM systems, we think that this concept is the single most important feature of Genome that differentiates it from all other O/RM systems (for the nitpicking, read the technical highlights section at the end).

A simple example explaining query encapsulation and reusability

Let’s have an example to explain what query encapsulation and reusability mean in practice. Imagine the following object model taken from the Northwind database:

A Customer has many orders consisting of OrderDetails. OrderDetail has a Quantity and points to the Product sold.

Implementing OrderDetail.Value

Let’s start by building some simple business logic on this object model. First, we want to calculate the Value of an OrderDetail, which is quite straightforward to implement as a property on the OrderDetail class:

public abstract class OrderDetail : Persistent
{

  public decimal Value
  {
    get
    {
      return
      this.Product.UnitPrice
      * this.Quantity;
     }    
  }

}

Implementing Order.Value

Next, we want to implement the Value of an Order that sums up all OrderDetail values of the Order. Now it already becomes more interesting. Basically, there are two common approaches to implementing Order.Value.

The first approach iterates through the OrderDetails of an Order on the client side, summing up all OrderDetail values:

public abstract class Order : Persistent
{

  public decimal Value
  {
    get
    {
      decimal ret = 0;
      foreach(OrderDetail od in
         OrderDetails)
        ret += od.Value;
      return ret;
    }
  }

}

From an encapsulation point of view, the code above is perfect as it reuses the business logic to calculate the Value of an OrderDetail. If the OrderDetail Value calculation is changed later on (e.g. to apply a discount or to take the UnitPrice from a property initialised on OrderDetail with the Product.Price when Order was created), calculating Order.Value would still work with these new rules applied.

However, from a database point of view, the code above is horrible, as it reads all OrderDetails (and associated Products) of an Order to the client just to sum up the Quantity * Product.UnitPrice and return a single value in the end. Hence, the second approach to implementing Order.Value is to write a specialised query for this use case:

public abstract class Order : Persistent
{

  public decimal Value
  {
    get
    {
      return
      (from od in this.OrderDetails
      select od.Quantity *
             od.Product.UnitPrice)
      .Sum();
    }
  }

}

Genome is able to translate the above LINQ query into a single SQL sum aggregate (note: the query above could be implemented with Genome’s OQL as well), returning only a single decimal value from the database when accessing the Order.Value property. While this is perfect for optimising database communication, the query above breaks the encapsulation of OrderDetail.Value as it duplicates the logic of calculating the Value of an OrderDetail. Whenever OrderDetail.Value is refactored (consider the examples given previously), the query for Order.Value also needs to be refactored. While this seems like a small problem in the given example, duplicating query logic in real world applications causes a lot of errors, inconsistencies and overhead to maintain.

The dilemma of encapsulation versus performance

So the dilemma we are trying to point out here is the choice a developer has to make between utilising the database in a performance-oriented way (thereby avoiding unnecessary data roundtrips) and encapsulating query logic (thereby avoiding unnecessary duplications that are hard to maintain).

We think the query logic of a database-driven application makes up a significant part of the overall application’s business logic, so a solution to this problem is a key benefit provided by Genome.

The Genome alternative for implementing Order.Value

Genome solves this problem by allowing you to encapsulate and map query logic in your domain model. In the given example, the Order.Value implementation can reuse the OrderDetail.Value property in LINQ or OQL, yielding a single database roundtrip while preserving encapsulation.

Genome allows you to express query logic in the mapping file where the Genome compiler can verify the query during compile time, preventing hard-to-detect runtime errors in your query logic. This compile time checking of queries in the mapping file is already available with Genome OQL and doesn’t require the use of LINQ.

The Order.Value hence is expressed in the mapping file as:

<Type name="Order">
 
  <Member name="Value" Oql="Sql.Sum([Value](OrderDetails))" />
 
</Type>

Similarly, when using LINQ, the property can also be mapped as:

<Type name="Order">
 
  <Member name="Value" Linq="(from od in
this.OrderDetails                                                   select od.Value).Sum()" />
 
Type>

Note that the two representations of the property in OQL and LINQ are considered equivalent by Genome and will yield the same SQL query during runtime.

It is up to the developer to decide whether there should be an explicit client side representation of the property implementation. If the property should always be used to query the database, it can be left abstract in the business model and Genome will code generate the query execution automatically:

public abstract class Order : Persistent
{

  public abstract decimal Value { get; }

}

Having done this, the value of an Order can be simply retrieved by accessing the Order.Value property:

Order o = GetSomeOrder();
Console.WriteLine(“Order value={0}”, o.Value);

Furthermore, the definition of Order.Value can be reused in other operations such as filtering and ordering. Consider the following code snippet that retrieves Orders with the top ten Order.Value:

Set<Order>orders = dd.Extent<Order>()
                    .OrderBy("[Value ascending]")
                    .GetRange(0, 10);

Again, the above query can be expressed with LINQ as well:

var orders = (from o in dd.Extent<Order>()
             orderby o.Value
             select o).GetRange(0,10);

Further reusing query logic: Customer.OrderVolume(int year)

Mapped query expressions can be easily reused in other query expressions. This way, complex queries can be composed out of fairly simple query sentences, preserving encapsulation and reducing the complexity of the query logic.

Imagine a Customer.OrderVolume(int year) method that returns the sum of all orders of the customer in a given year:

public abstract class Customer : Persistent
{

  public abstract decimal OrderVolume(int year);

}

The mapping for this method can be easily expressed in the Genome mapping file, reusing the Order.Value property and filtering the Orders collection of a Customer by the given year:

<Type name="Customer">
 
  <Member name="OrderVolume"
signature="System.Int32"
   Oql="Sql.Sum([Value]Orders[o:
o.OrderDate.Year==year])"
  />
 
</Type
>

Again, having mapped this property doesn’t limit you to just querying for the OrderVolume of a Customer instance. OrderVolume can be reused anywhere in the query logic, for example to retrieve all Customers, where the OrderVolume for a given year was larger than a certain amount:

Set<Customer> customers = dd.Extent<Customer>()                             .Where("OrderVolume({0})>{1}", year, amount);

Again, the query can be just as well implemented using LINQ:

var customers = from c in dd.Extent<Customer>()
                where c.OrderVolume(year) > amount
                select c;

The query above reuses Order.Value, OrderDetail.Value and Orders of customer to filter for the OrderVolume of Customers.