Introduction
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
{
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:
[Serializable]
public class Lite<T> : Lite
where T : class, IIdentifiable
{
public Lite(int id)
public Lite(Type runtimeType, int id)
public T EntityOrNull{get;}
public T Entity {get;}
}
[Serializable]
public abstract class Lite : Modifiable
{
public int Id{get;}
public int? IdOrNull{get;}
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
{
public static Lite<T> ToLite<T>(this T entity) where T : class, IIdentifiable
public static Lite<T> ToLiteFat<T>(this T entidad) where T : class, IIdentifiable
public static Lite<T> ToLite<T>(this T entidad, bool fat) where T : class, IIdentifiable
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.