Signum Framework Logo
"Open framework that encourages convention over configuration, using C# code,
not XML files, to model at the right level of abstraction and achieve deadlines.
...but also has a full Linq provider, and syncs the schema for you!"



Source code




Unfortunately, in .Net 4.0 a new class with name Lazy is included in mscorlib.dll (System namespace). It would be really inconvenient to use the same name so we have decided to change it to Lite<T> in advance. Sorry for the inconvinience.

Every Persistence Framework has to deal with laziness in some way. Linq to SQL and Entity Framework, for example, follow a runtime lazyness approach, meaning that you can define at runtime if a relationship is lazy or not.

Singum Framework, however, needs you to define that a field/property type as Lite<T> instead of T to create a lazy relationship (where T is some IIdentifiable).

That means that laziness is structural (you have to define it at compile time), and also non-transparent (since you have to explicitly load a Lite before accessing it).

This is mandatory because Signum Entities are meant to be easy Serializable, so you can't pretend that the database is always going to be there. For the same reason, lites affects validations, since it's not safe to define your IntegrityCheck based on a Lite relationships. Validation ends where lites appear.

Given that lites are an important decision when designing your entities, hiding it in the property getter/setter is not a good idea because you will make your entities dependant on the engine.

 Lite<PersonDN> person;
 public PersonDN Person
   //Don't do this!!
    get { return person.Retrieve(); } 
    set { Set(ref person, value.ToLite(), ()=>Person); }

Usually, any kind of mismatch between field and property types is not recommended, since is would affect Linq queries as well.

Lite class

This is the Lite class:

public class Lite<T> : Lite
   where T : class, IIdentifiable
   public Lite(int id)
   public Lite(Type runtimeType, int id)
   public T EntityOrNull{get;} //Returns null if not loaded
   public T Entity {get;} //Throws InvalidOperationException if not loaded

[Serializable] public abstract class Lite : Modifiable { public int Id{get;} //Throws InvalidOperationException if new public int? IdOrNull{get;} //Returns null if new public Type RuntimeType {get;} public int RefreshId(); public void SetEntity(IdentifiableEntity ei); public void ClearEntity(); }

Splitting Id in Id/IdOrNull and Entity in Entity/EntityOrNull is new from Signum Framework 2.0

Thin and Fat

First of all, there's no such thing as a Lite<T> pointing to null. A Lite<T> pointing to null is just null.

However, Lite<T> could have two possible states, Thin or Fat
  • Thin: Stores only the type of the field, the Id and a textual description of it (ToStr).
  • Fat: The lite actually has a reference to the related Entity and will be Saved or Serialized with it.

In the current implementation, every Lite retrieved from an entity's field will be Thin (Maybe in the future we will add facilities to specify at runtime which of them should be Fat when retrieving). But once retrived it will store the entity. If needed you can return it to Thin calling ClearEntity()

On the other hand, every Lite pointing to a new entity needs to be Fat because the new entity doesn't have an Id jet there's no way to identify it but by reference.

Lite<T> and RuntimeType

We have said that a Lite<T> stores the type of the field (as well as the Id and ToStr). This is necessary since we have to allow Polymorphic Foreign Keys even on Lites. It's legal to store a GiraffeDN in a Lite<IAnimal>, so this Lite stores typeof(GirafeDN) in his RuntumeType field. Se more about that in Inheritance.

Database Side Considerations

There's just no one. Using Lite<T> instead of T has no effect on the database. This is good since you can change the lazyness of a relationship without running any script over your data.

When retrieving a Lite<T>, it gets the ToStr value from the actual table of the entity.

Extension Methods

Lite has some public Constructors but they are meant for advanced scenarios (i.e: when you have to create Lites at runtime for example).

Usually, what you use, and what the Query engine supports, is the extension methods: ToLite and ToLiteFat

  public static class LiteUtils
     //The first creates a Lite in Thin state, and throws an Exception if the entity is New
     public static Lite<T> ToLite<T>(this T entity) where T : class, IIdentifiable
     //The second one creates a Lite in Fat state
     public static Lite<T> ToLiteFat<T>(this T entidad) where T : class, IIdentifiable     

//The third has one behaviour or the other depending of the second parameter, fat. //It's useful when using the same code in the client and server side, and fatness of lazies are the only differences (not very often) public static Lite<T> ToLite<T>(this T entidad, bool fat) where T : class, IIdentifiable

//Lite conversion. New in SF 2.0 public static Lite<T> ToLite<T>(this Lite lite) where T : class, IIdentifiable }

All this methods have also another overload that take a different toStr as a parameter. This is usefull when Lites are used for UI purposes (ComboBox, SearchWindow...) and it's also available on queries.

We could have created a ToLiteAuto that creates fat Lites only if the entity is new, but this have two potential problems: First, everybody will be using it to avoid thinking, but fatness is an important thing and you should pay attention on it. Second, usually you should know in advance if the entity you try to 'lite' is going to be new or not, so this will just hide your intentions to code readers. So we did't add this method.

Creative Commons License Signum Framework Site by Signum Software is licensed under a Creative Commons Attribution 3.0 License.
Powered by ScrewTurn Wiki version