Validation and editable collections

Validation and editable collections

Old forum URL: forums.lhotka.net/forums/t/7074.aspx


j055 posted on Wednesday, June 10, 2009

Hi

I've created an editable collection based quite heavily on the Roles and Role classes in the ProjectTracker.Library. I'm also using the CslaDataSource in a web page with a GridView to display the list and a DetailsView to insert a new item. The code also closely resembles the RolesEdit.aspx page.

My validation is simple and contains a couple of required string rules. When I insert a new item I notice that these rules were not checked. I added the CheckRules method to the child and it now validates the empty fields.

        protected override void Child_Create()
        {
            LoadProperty(CreateDateProperty, DateTime.Now);
            LoadProperty(ModifyDateProperty, DateTime.Now);
            ValidationRules.CheckRules();
        }

I'm puzzled by a few things:

1. When I try to insert a valid new item from the DetailsView I get a validation exception ' Object is not valid and can not be saved' without any broken rules. I don't know why it shouldn't validate.

2. I notice that whether the item validates or not the item is added to the collection and therefore bound to the GridView.

I realize that I could do more in the UI to stop this from being a problem but I want to make sure the business objects are performing appropriately first.

Is my code suspect or is this the way the framework should behave? Can I implement the business objects differently to make things work as expected?

Many thanks
Andrew

 

 

RockfordLhotka replied on Wednesday, June 10, 2009

LoadProperty() very specifically does NOT run any business, validation or authorization rules. It is a light-weight way to set the property value without incurring any overhead.

So if you want the rules to be checked, you must explicitly call CheckRules() once the values are set.

Regarding your issue 1 - I recommend using the debugger to walk through the code in your web page where you copy the values from the form postback into your child object. It is likely that some value is being set (or not set) in a property that you aren't expecting, resulting in the object not being valid.

Regarding your issue 2 - with a web app it is really up to you whether the new child is in the collection or not. With a smart client technology data binding will add child objects to the collection following a set of rules - but with the web it is less automated, and you can choose how it works.

For example, you might choose to have your postback code create and load the child object with data from the web form, then look to see if the object IsValid to decide whether to add it to the collection.

j055 replied on Thursday, June 11, 2009

Hi

Thanks for the explaination. I found that the error was from the invalid item already in the collection from the previous postback. I was only checking the broken rules of the newly inserted item but the BO was obviously trying to save the other items still marked as IsNew.

So what I do now is remove the item from the collection the first time I get a ValidationException, e.g.

protected void RolesDataSource_InsertObject(
object sender, InsertObjectArgs e)
{
Roles obj = GetRoles();
Role role = obj.AddNew();
try
{
DataMapper.Map(e.Values, role);
Session["currentObject"] = obj.Save();
e.RowsAffected = 1;
}
catch (ValidationException ex)
{
ErrorLabel.Text = ex.Message;
obj.Remove(role);
e.RowsAffected = 0;
}
catch (DataPortalException ex)
{
ErrorLabel.Text = ex.BusinessException.Message;
e.RowsAffected = 0;
}
catch (Exception ex)
{
ErrorLabel.Text = ex.Message;
e.RowsAffected = 0;
}
}

Seems to work under initial testing.

Thanks again.
Andrew

j055 replied on Thursday, June 11, 2009

Maybe this is a bit better:

Roles obj = null;
Role role = null;
try
{
obj = GetRoles();
role = obj.AddNew();
DataMapper.Map(e.Values, role);
Session["currentObject"] = obj.Save();
e.RowsAffected = 1;
}
catch (ValidationException ex)
{
ErrorLabel.Text = ex.Message;
if (obj != null) obj.Remove(role);
e.RowsAffected = 0;
}
catch (DataPortalException ex)
{
ErrorLabel.Text = ex.BusinessException.Message;
e.RowsAffected = 0;
}
catch (Exception ex)
{
ErrorLabel.Text = ex.Message;
e.RowsAffected = 0;
}

Copyright (c) Marimer LLC