Logo

NHibernate

The object-relational mapper for .NET

Burrow

This page is converted from the old nhforge.org Wiki. First published by: kailuowang on 09-07-2008, Last revision by: kailuowang on 04-27-2009

Table of Contents

Stateful Fields

StatefulField Attributes


We all know that in the stateless ASP.NET framework, persisting page/control's states of entity type could be a cumbersome task - for example a customerEditor.ascx needs to remember which customer it's editing. One of the common solutions is to store the Id of the entity as a value of a hidden field or into the ViewState, then load the entity from the id when needed. The code will be something like

private Customer cust;
public Customer Cust {
    get
    {
        if (ViewState["custID"] == null) return null;
        if (cust == null)
            cust = CustomerDAO.Instance.FindById((int)ViewState["custID"]);
        return cust;
    }
    set {
        cust = value;
        if (value == null)
            ViewState["custID"] = null;
        else
            ViewState["custID"] = value.Id;
    }
}

This approach has a couple of shortcomings. First, as you can see here, it's cumbersome to do the null judgement and converting type for the Id object. If you have codes all over the application, it's duplicated code. Secondly and more importantly, it requires either ViewState or HiddenField, each has its own problem: ViewState could be disabled; HiddenField does not work well within Ajax.Asp.Net's UpdatePanel as only the HiddenFields in the updating UpdatePanel will reflect the change you made to its value.
Now Burrow offers a new approach - StatefulField attributes.
[StatefulField] attribute is the most basic one. Here is an example:

[StatefulField]
protected int count = 1;

You mark a field of your control/page with the attribute [StatefulField], the value will be persistent over postbacks. [StatefulField] can be used for fields of types that are serializable - preferably primitive fields. Normally for this kind of fields, you can store them in the ViewState. However [StatefulField] attribute make the code cleaner and more importantly it can work when ViewState is disabled ( sure, there is ControlState, but this is a lot easier than ControlState isn't it? )
[EntityField] and [EntityFieldDeletionSafe] are the enhanced versions of [StatefulField]. Both can only be used to persist entity fields in a control/page. Here is an example:

public partial class CustomerEditor : UserControl
{
   [EntityFieldDeletionSafe]
   protected Customer customerBeingEdited;
 
   [EntityField]
   protected User editingAdmin;
 
}

The CustomerEditor user control is written for administrator to edit a certain customer's profile. The above code uses the field customerBeingEdited to store the customer it's currently working on. The editingAdmin field is used to store the administrator user that is currently working with the system. Please note that [EntityField] and [EntityFieldNullSafe] should and can only be used on fields of entities that are already persisted. You cannot use them on transient entities. The major behavior difference between [EntityField] and [EntityFieldDeletionSafe] is that when you delete the entity without setting the field to null, [EntityField] will cause an Exception next time Burrow load entity value for it while [EntityFieldDeletionSafe] won't. Behind the scene, that's because that [EntityField] is using ISession.Load() to load the entity while [EntityFieldDeletionSafe] is using ISession.Get(). So the other interpretation here is that [EntityField] can return a proxy if your entity is set as LazyLoad=true, which could be a performance gain.
[ConversationalField] is a special version designed only for long Burrow Conversation. In long Burrow Conversation, you probably need to store some data that needs to have the same life span as the conversation. [ConversationField] attribute can be used for such fields. Here is an example:

public partial class Checkout: Page {
    [ConversationalField]
    protected Order placingOrder;
}

A checkout page that uses long Burrow Conversation stores the currently processing order in the placingOrder field. Marked with [ConversationalField] attribute, the value of this field will have the same life span as the conversation as its value is actually stored in the conversation instance. [ConversationalField] can be used on all types - not only entity but also non-entity types.
Important Notes:

  • For now, all Burrow field attributes ( [StatefulField], [EntityField], [EntityFieldDeletionSafe] or [ConversationalField] ) can only be used against protected or public fields of UserControls or Pages. Private fields marked with these attribute will be simply ignored.
  • The value of these Burrow fields becomes ready at PreLoad, which is about the same as ViewState On the other hand, if you change their value after PreRenderComplete, the change won't persist.
  • Burrow inspects the whole control tree at the beginning of every request, you can prevent Burrow from doing this to a particular control with 2 options: 1) add an attribute (IgnoreStatefulFields) to the control class or 2) let the control implement an interface - IStatefulFieldsControl .

© NHibernate Community 2024