Csla Data Mapper and Dependant Properties, Order of

Csla Data Mapper and Dependant Properties, Order of

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

richardb posted on Thursday, November 17, 2011

OK I'm using the Csla Data Mapper in an ASP.Net webforms UI (I dream of doing MVC one day) and have a boolean property firing which sets a default date on another property - the user can also set the date in the UI.

When mapping, if the date control maps first it gets set to e.g. 18th Nov, but then the boolean setproperty fires and resets my date to today (e.g. 17th Nov).

Is there anyway to have the business layer object indicate the order I want the data mapper to fire the property mapping in, or will I nedd to / be better off removing the DataMapper and do it manually mapping the properties in my desired order.

But of course, even if I do it manually the UI developer would need to know the business property dependancies.  Not such a problem as they have the source code, but what if they didn't have the source code?





RockfordLhotka replied on Thursday, November 17, 2011

It has been a long time since I looked at DataMapper, but I think you can control the order by creating your own DataMap.

By default DataMapper uses reflection to find the properties, and it loops through them. It might be the case that if you provide a DataMap it walks through the elements in the DataMap in order. It might not work that way - I honestly don't remember - you can look at the code to see.

Otherwise you'll probably need to do manual mapping.

Though another alternative is to suppress rules during the mapping process. This is a feature of CSLA 4, and can be useful when batch loading properties in scenarios like a web site. The feature is discussed in the Using CSLA 4: Creating Business Objects ebook.

richardb replied on Friday, November 18, 2011

I think manual mapping is what I'll need to do in my scenario - thanks for the quick response.

ALthough I may look at extending the DataMapper - I wonder if I can add custom attributes to the properties, and then have the DataMapper fetch the properties in order and map that way.


<AttributeUsage(AttributeTargets.Property, _
     AllowMultiple:=False, Inherited:=False)> _
Public Class BindingOrderAttribute
    Inherits System.Attribute
    Private m_BindingOrder As Integer
    Public Sub New(ByVal bindingOrder As Integer)
        m_BindingOrder = bindingOrder
    End Sub
    Public Property BindingOrder() As Integer
            Return m_BindingOrder
        End Get
        Set(ByVal Value As Integer)
            m_BindingOrder = Value
        End Set
    End Property
End Class

Then do this on my properties....

Private Shared ReadOnly _isSignOffSMProperty As PropertyInfo(Of Boolean) = RegisterProperty(Of Boolean)(Function(p As BusinessCase) p.IsSignOffSM)     <BindingOrder(0)> _     Public Property IsSignOffSM() As Boolean         Get             Return GetProperty(_isSignOffSMProperty)         End Get         Set(ByVal value As Boolean)             SetProperty(_isSignOffSMProperty, value)             If value = True Then                 Me.SignOffSMDate = New SmartDate(Date.Now).ToString                 SetProperty(_SMUserIDProperty, Csla.ApplicationContext.User.Identity.Name)             Else                 Me.SignOffSMDate = New SmartDate(True).ToString                 SetProperty(_SMUserIDProperty, "")             End If         End Set     End Property

Private Shared ReadOnly _SignOffSMDateProperty As PropertyInfo(Of SmartDate) = RegisterProperty(Of SmartDate)(Function(p As BusinessCase) p.SignOffSMDate, New SmartDate(True))     <BindingOrder(1)> _      Public Property SignOffSMDate() As String         Get             Return GetPropertyConvert(Of SmartDateString)(_SignOffSMDateProperty)         End Get         Set(ByVal value As String)             SetPropertyConvert(Of SmartDateString)(_SignOffSMDateProperty, value)         End Set     End Property



and then have another MapInBindingOrder method


 public static void Map(
      System.Collections.IDictionary source,
      object target, bool suppressExceptions,
      params string[] ignoreList)

//TODO: Can we modify this to reflect and get properties on object in our custom attribute order ascending,
//and then map the values across???????

       List<string> ignore = new List<string>(ignoreList);       foreach (string propertyName in source.Keys)       {         if (!ignore.Contains(propertyName))         {           try           {             SetPropertyValue(target, propertyName, source[propertyName]);           }           catch (Exception ex)           {             if (!suppressExceptions)               throw new ArgumentException(                 String.Format("{0} ({1})",                 Resources.PropertyCopyFailed, propertyName), ex);           }         }       }     }

Is this approach sound? Technically doable?

I think I like it better as the business object is indicating the best way to map.

Copyright (c) Marimer LLC