Sunday, March 20, 2011

Generating dynamic forms :: part 1


Let me start out by saying, I know there are already a gazillion posts on the subject of generating dynamic forms using asp.net. I'm not posting this to teach the world something new, yet just to give in on the subject a little bit. This task is just so common that it's worth having a lot of examples out there and let people choose which suits them the best.

Generating dynamic forms can be done in so many different ways, and there is no 'right' way or 'wrong' way. Each way has its specific pros and cons.
I was put up to the task of creating dynamic forms from data in the db, again, this time for a web application at work. I searched the internet for articles on the subject to get ideas from and to get a direction. I saw so many different ways to do this, and got lost in all the information that i just decided to think it through on my own and give it my best shot.

I will post about the solution I came with in parts (since i'm guessing it will be long...).
In the first part, I will talk about making some basic decisions before starting to program.

Tehcnologies
I'm creating the application with asp.net. C# on the server side. For the client I'll be using javascript obviously, and leaning heavily on the jQuery framework since I know it the best.
In my DAL (Data Access Layer), I'll be using Fluent NHibernate to work with my DB (also a big fan of FNH).

Describing the forms
My forms are built like most forms - Each control is made up from a label and an input of some sort. The basic inputs are a textbox, a checkbox, a combo. Combo's for example can have multiple values, so they'll need to receive a list of values from somewhere. Each control will also need to implement validations.
I will also want to be able to implement special inputs like a datepicker which has a calendar you can choose from, or an address control which the street combo is linked cascadingly from the city combo.

So, so far, im guessing each control in the form will be described by the properties : Label, Name, Type, ListOfValues (this will be a list), Validations (also a list), CurrentValue.

Creating the forms
In my application, I want the forms to be opened in client-side dialog windows, because the user is supposed to view an available list of forms to fill out, open some of them, and fill their values. In the end, the user can choose to save all the information in the forms.
So, I will be implementing the creation of the forms on the client via javascript. I will render to the html source, all of the forms objects in json format, and when the user chooses to open a specific form, I will create it specifically in a dialog window.
I will then save the values into the json, and using ajax, send the information back to the server.

Form Interactions
Each control will have a 'Validate' method, so i can choose to call it when i want. Obviously, the best time to do this is when the user submits.
Submitting the form and a button for submition can be implemented on my own, with no connection to the form builder. I want my generic form builder to help me in the future in every situation, and i can't predict what submition scenarios i'll need in the future so i'll just implement it on my own everytime.

Submitting the form
Like stated earlier, saving the form values will go directly back into the json object where they came from. I will then send it to the server via ajax, and do the db updating on the server side.

Coming up...
In the next post I will start getting into the nitty gritty.
I will show how I built my db representation of the forms - What my entities look like, what are their properties and how they are built.

Saturday, March 5, 2011

Fluent NHibernate - Working with Database Views


So, it turns out you can work with Views with Fluent NHibernate just as you were to work with tables. All you need to is define your entity with the name of the view, instead of the table name.

example :
public class UserEntity
{
    public virtual int UserId { get; private set; }
    public virtual String FirstName { get; set; }
    public virtual String LastName { get; set; }
    public virtual int UserStatusId { get; set; }
    public virtual String UserStatus { get; set; }
}

public class UserEntityMap : ClassMap<UserEntity>
{
    public UserEntityMap()
    {
        Table("view_Users");  // this is mapped to a view, and not a table

        Id(x => x.UserId);
        Map(x => x.FirstName);
        Map(x => x.LastName);
        Map(x => x.UserStatusId);
        Map(x => x.UserStatus);  // This field is from another table
                                 // it is from a seperate code table that describes the different statuses in the system
    }
}

An exception is thrown, when trying to update the entity that is mapped to a view. The problem is actually because when working with a view, you cannot execute an update query that updates rows on different tables. It will only work when updating rows on one table in the view.

In order to get around this, we need to tell the mapping that some properties aren't to be updated. This will solve the problem.

example :
public class UserEntityMap : ClassMap<UserEntity>
{
    public UserEntityMap()
    {
        Table("view_Users");  // this is mapped to a view, and not a table

        Id(x => x.UserId);
        Map(x => x.FirstName);
        Map(x => x.LastName);
        Map(x => x.UserStatusId);
        Map(x => x.UserStatus).Not.Update();
    }
}

Marking the mapping class with '.Not.Update()' tells FNH to return false on the update property of this field.
Likewise, we can also mark an attribute as '.Not.Insert()' and then the field will only be updatable, or mark a field as '.ReadOnly()' and the field will act as if it has a private set.