Friday, October 23, 2009

Arbitrary keys & hierarchies, part 5. Key providers

In the previous posts we discussed the evolution of Key, its structure and the ways to work with keys. Now it’s time to answer the question: where keys come from? But first, let’s see scenarios where we do need new keys.

As you know, Entity instance is uniquely identified by key and Entity.Key property is immutable during whole Entity’s lifecycle. The only moment when Entity.Key property can be set is the moment of Entity construction. There are two scenarios and DataObjects.Net v4 supports both of them:

1. Values of identity fields are provided by outer code (not ORM but application is responsible for this). In this scenario user code is responsible for passing identity values directly to Entity constructor where these values are automatically transformed into key.

// Use this constructor for types with explicitly set identity values
protected Entity(params object[] values)

Example:

[HierarchyRoot]
public class Book : Entity
{
  [Field, Key]
  public string ISBN { get; private set; }

  // Accepts identity value (ISBN) and passes it to the base Entity constructor
  public Book(string isbn)
    : base(isbn) { }
}

2. Values of identity fields are provided by ORM (or with the help of ORM). This scenario might involve usage of database identity generators, tables with auto-increment column as well as any custom identity generators, e.g. Guid generator in order to get identity values for an Entity and build its key.

// Use this constructor for types with auto-generated identity values
protected Entity()

Example:

[HierarchyRoot]
public class Book : Entity
{
  [Field, Key]
  public int Id { get; private set; }

  // Nothing to be done here as base empty Entity constructor will be called automatically
  public Book() { }
}

While the first scenario is clear and doesn’t need any ORM participation at all (except creating key from values passed to constructor), the second one is not so clear because it requires ORM to know how to obtain the next unique identity values for the specified persistent type. To solve this task the concept of key providers was introduced in DataObjects.Net v4. KeyProviderInfo is a type from Domain model which contains all necessary information concerning generation of unique keys for particular persistent type(s), including:

  • type of identity generator implementation;
  • structure of key (key columns and descriptor of tuple);
  • size of key cache, if generator supports caching;
  • mapping name, if generator is mapped to a particular database entity;
  • etc.

DataObjects.Net v4 contains several key generator implementations both for In-Memory & SQL storages out of the box. They are called default key generators. They support caching and can be used for persistent types with exactly one identity field. This means that for persistent types with complex key (more than one identity field) custom key generator must be provided by user. In order to increase key generator performance and to simplify persistent interfaces support we made the following architectural decision:

We try to share single instance of every key generator type between all hierarchies it can serve.

All hierarchies which have identical key structure and identical key generator type, e.g. typeof(MyKeyGenerator), are served by the same instance of MyKeyGenerator. In other words, we create only one instance of each key generator type, registered in Domain. For example:

[HierarchyRoot]
public class Book : Entity
{
  [Field, Key]
  public int Id { get; private set; }

  public Book() { }
}

[HierarchyRoot]
public class Author : Entity
{
  [Field, Key]
  public int Id { get; private set; }

  public Author() { }
}

Here we have 2 hierarchies with default key generator (default key generator is used unless custom key generator is explicitly defined via KeyGeneratorAttribute). As both hierarchies have identical key structure (one field type of int) and the same type of key generator – default key generator, then only 1 key generator (Int32-Generator actually) will be created and it will serve both hierarchies at once. This means that sequence of Book identifiers as well as sequence Author identifiers won’t be strictly sequential. Say, one can get 1,2,3,6 for Book identifiers and 4,5,7,8,9 for Author identifiers. Nevertheless, all keys produced by this key generator are unique and can be used in any number of hierarchies which can be served by this key generator type without any restrictions.
The only one “negative effect” of this scheme is the presence of gaps in identifier sequence for concrete persistent type. But does it matter? Such gaps are common as objects don’t live forever, sometimes they are removed.

In the next post I’ll tell you about complex keys and custom key generators and their future.

Part 4. Working with keys, Part 6. Identity fields

CodeProject

No comments:

Post a Comment