Object factory support for read only objects

Object factory support for read only objects

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


jkollath posted on Friday, February 27, 2015

I am trying to implement object factory support with a read only object and would like to know the best way to populate it.

JonnyBee replied on Saturday, February 28, 2015

Hi,

This very similar to  an editable object - you just leave out the state management commands.
Make sure to use the helper methods in ObjectFactory base class and use managed properties in your read-only object.

Sample her shown for a list:

public object Fetch(string criteria)
{
  var list = (CustomerList)MethodCaller.CreateInstance(typeof(CustomerList));
 
 
  // just sets up some mock data - could com from Xml,L2S, EF or othere sources unknown to the BO itself. 
  var customers = new[]
           {
             new CustomerData {Id = 1, Name = "Baker, Jonathan"},
             new CustomerData {Id = 2, Name = "Peterson, Peter"},
             new CustomerData {Id = 3, Name = "Olsen, Egon"},
             new CustomerData {Id = 4, Name = "Hansen, hans"}
           };
 
  list.RaiseListChangedEvents = false;
  this.SetIsReadOnly(list, false);
 
  // tranform to my lists child type
  list.AddRange(customers.Select(p => new CustomerInfoFactory().GetCustomerInfo(p)));
 
  this.SetIsReadOnly(list, true);
  list.RaiseListChangedEvents = true;
 
  return list;
}

 

public class CustomerInfoFactory : ObjectFactory
{
  public Business.CustomerInfo GetCustomerInfo(DataEntitites.CustomerData data)
  {
    var customer = (CustomerInfo)MethodCaller.CreateInstance(typeof(CustomerInfo));
 
    LoadProperty(customer, CustomerInfo.IdProperty, data.Id);
    LoadProperty(customer, CustomerInfo.NameProperty, data.Name);
 
    return customer;
  }
}

 

 

Kris replied on Tuesday, March 03, 2015

Hi Johnny,

Thanks for that. But when I use the IntelliSense, somehow it is not pulling up the property name.

Ex: When I gave CustomerInfo  & then a period, it shows the list of all methods (not properites). It shows the property only when I change the promerty to static  (but the get method in that property is called by another staitic method)

Thanks,

Kris

JonnyBee replied on Tuesday, March 03, 2015

Your code must make sure that the PropertyInfo is defined as public.

Kris replied on Wednesday, March 04, 2015

Hi Jonny,

This is what we are facing.

public static readonly PropertyInfo<System.Int32> _CustomerIDProperty = RegisterProperty<System.Int32>(p => p.CustomerID, "Customer I D");

              
        public System.Int32 CustomerID
        {
            get { return GetProperty(_CustomerIDProperty); }
        }

 

public class CustomerInfoFactory : ObjectFactory
{
  public Business.CustomerInfo GetCustomerInfo(DataEntitites.CustomerData data)
  {
    var customer = (CustomerInfo)MethodCaller.CreateInstance(typeof(CustomerInfo));
 
    LoadProperty(customer, CustomerInfo._CustomerIDProperty, data.Id);

But we want to refer "CustomerID" property instead of "_CustomerIDProperty"

Ex:  LoadProperty(customer, CustomerInfo.CustomerID, data.Id);

I tried changing the actual property to static, but it won't work since the get operator is calling  _CustomerIDProperty

Thanks

JonnyBee replied on Friday, March 06, 2015

Hi, 

You have 2 options:

 

  1. Use LoadProperty with the PropertyInfo object as parameter 
  2. Implement a property setter (internal?) and use InternalsVisibleToAttribute to make internal methods visible to ObjectFactory

 

You cannot use the actual property as a parameter to LoadProperty.

In the "old days" you could either use a "propertyname" or the PropertyInfo. In later versions IIRC there is only support for PropertyInfo as a parameter to LoadProperty. 

jkollath replied on Friday, March 06, 2015

I'm stuggling with the syntax of option 1.  In this example I'm trying to set the value of AccountID in a read-only class with its definition below. 

public AccountInfo Map(SafeDataReader reader)
      {
          var item = (AccountInfo)Methodcaller.CreateInstance(typeof(AccountInfo), true);
          using (BypassPropertyChecks(item))
          {
               LoadProperty( item, PropertyInfo(<System.Int32> AccountInfo.AccountID), 123);  
               . . . 
          }
     }

 

 

private static readonly PropertyInfo<System.Int32> _accountIDProperty = RegisterProperty<System.Int32>(p => p.AccountID, "Account ID");

        [System.ComponentModel.DataObjectField(true, true)]
        public System.Int32 AccountID
        {
            get { return GetProperty(_accountIDProperty); }

        } 

 

 

ajj3085 replied on Friday, March 06, 2015

public AccountInfo Map(SafeDataReader reader)
      {
          var item = (AccountInfo)Methodcaller.CreateInstance(typeof(AccountInfo), true);
          using (BypassPropertyChecks(item))
          {
               LoadProperty( item, AccountInfo._accountIDProperty, 123);  
               . . . 
          }
     }

public static readonly PropertyInfo<System.Int32> _accountIDProperty = RegisterProperty<System.Int32>(p => p.AccountID, "Account ID");

You need to make the PropertyInfo in your BO public and then use it as the second parameter of LoadProperty.

jkollath replied on Friday, March 06, 2015

I'm almost there, but am getting an error when referencing _accountIDProperty:  "PetShop.Business.AccountInfo' does not contain a definition for '_accountIDProperty". I don't know what it means by definition given that the property definition is public static

        namespace petshop.business
        public static readonly PropertyInfo<System.Int32> _accountIDProperty = RegisterProperty<System.Int32>(p => p.AccountID, "Account ID");

        [System.ComponentModel.DataObjectField(true, true)]
        public  System.Int32 AccountID
        {
            get { return GetProperty(_accountIDProperty); }
        }

        namespace Petshop.Data
        public AccountInfo Map(SafeDataReader reader)
        {
            var item = (AccountInfo)Methodcaller.CreateInstance(typeof(AccountInfo), true);

            using (BypassPropertyChecks(item))
            {
                LoadProperty(item, AccountInfo._accountIDProperty, reader.GetInt32("AccountID"));
                LoadProperty(item, AccountInfo._uniqueIDProperty, reader.GetInt32("UniqueID")); 
                LoadProperty(item, AccountInfo._emailProperty, reader.GetString("Email"));
                LoadProperty(item, AccountInfo._firstNameProperty, reader.GetString("FirstName"));
                LoadProperty(item, AccountInfo._lastNameProperty, reader.GetString("LastName"));
                LoadProperty(item, AccountInfo._address1Property,  reader.GetString("Address1"));
                LoadProperty(item, AccountInfo._address2Property, reader.GetString("Address"));
                LoadProperty(item, AccountInfo._cityProperty, reader.GetString("City"));
                LoadProperty(item, AccountInfo._stateProperty, reader.GetString("State"));
                LoadProperty(item, AccountInfo._zipProperty, reader.GetString("Zip"));
                LoadProperty(item, AccountInfo._countryProperty, reader.GetString("Country"));
                LoadProperty(item, AccountInfo._phoneProperty, reader.GetString("Phone"));
            }
            return item;
        }

ajj3085 replied on Friday, March 06, 2015

With what you have posted here that should be compiling.  Try deleting ._accountIDProperty in your Map method, and then type the . after AccountInfo again on that line and see if you can find the property in intellisense.  Maybe its _accountIdProperty ?  Or maybe yoiu just need to recompile the business project before it works. Also double check your references; I assume both projects are in the same solution, make sure your reference in the Data project is using a Project Reference to the Business project. 

Are you using Resharper by any chance?

JonnyBee replied on Saturday, March 07, 2015

Hi,

And there is no point in having using BypassPropertyCheck with this code.

BypassPropertyCheck is only effective for Editable objects where you rather than use LoadPropery call the actual property setter in the object and want the SetProperty to work as LoadProperty.

Otherwise the code looks to be correct..

Make sure that your project references is not off (ex: dal references an assembly in bin folder and not the project in solution)

jkollath replied on Tuesday, March 10, 2015

I had to add "using Csla.Reflection" before I could see MethodCaller in the item declaration.  I got a good compile after that.

Thanks to all for the assist.

Kris replied on Thursday, March 05, 2015

Hi Jonny, did you got my previous reply

 

Thanks,

Kris

Copyright (c) Marimer LLC