RelationshipTypes.PrivateField always throws "Attempt to read/load private field property in managed properties"

RelationshipTypes.PrivateField always throws "Attempt to read/load private field property in managed properties"

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


artwang posted on Thursday, March 31, 2011

From my reading from some discussion, RelationshipTypes.PrivateField should work in AddBusinessRules with version 4 by now. Can someone please point out what I miss here:

private FieldMappingCases _fieldMappingCases = FieldMappingCases_property.DefaultValue;
        private static PropertyInfo<FieldMappingCases> FieldMappingCases_property =
RegisterProperty<FieldMappingCases>(p => p.FieldMappingCasesCollection, "FieldMappingCases"RelationshipTypes.PrivateField);        
        public FieldMappingCases FieldMappingCasesCollection
        {
            get
            {
                return GetProperty(FieldMappingCases_property, _fieldMappingCases);
            }
            //set { SetProperty(FieldMappingCases_property.Name, ref _fieldMappingCases, value); }
        }

then in AddBusinessRules():
            BusinessRules.AddRule(new OnlyOneDefault { PrimaryProperty = FieldMappingCases_property, AffectedProperties = { } });

        private class OnlyOneDefault : Csla.Rules.BusinessRule
        {
            protected override void Execute(Csla.Rules.RuleContext context)
            {
                var target = (FieldMapping)context.Target;
                FieldMappingCases fieldMappingsases = (FieldMappingCases)target.ReadProperty(FieldMappingCases_property);
                if (fieldMappingsases.IsOnlyOneDefault == false)
                {
                    context.AddErrorResult("There has to be one and only one Default FieldMappingCase");
                }
            }
        }

The target.ReadProperty calls into the following CSLA code:

      if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))
        throw new InvalidOperationException(Resources.PropertyGetNotAllowed);
      P result = default(P);
      FieldManager.IFieldData data = FieldManager.GetFieldData(propertyInfo);
   
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
    public IFieldData GetFieldData(IPropertyInfo propertyInfo)
    {
      if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) == RelationshipTypes.PrivateField)
        throw new InvalidOperationException(Resources.PropertyIsPrivateField);
Hence the error.

Is there a new version which allows RelationshipTypes.PrivateField in validation?

Thx!

JonnyBee replied on Friday, April 01, 2011

Try to change

 var mappingCases = (FieldMappingCases)context.InputPropertyValues[PrimaryProperty];

The rule engine will extract all InputProperties into InputPropertyValues for you.

Generic versions of ReadProperty/LoadProperty are exclusively for ManagedProperties. However there is a non-generic ReadProperty that will also handle private properties. In this case you could also use:

 var mappingCases = (FieldMappingCases)ReadProperty(PrimaryProperty);

as primary property is non-generic IPropertyInfo.

StefanCop replied on Friday, September 23, 2011

Hi, I've got similar problem: 

I want to write a Validation Rule on some managed properties, where the primary property is a LazyLoad. If it's not yet loaded the rule always succeeds, otherwise the a check is executed. The scenario behind ist that some screens bind (and therefore load) the property, whereas other don't and we can benefit from not loading.  

As artwang pointed, it's neither possible to define InputProperty(Values) nor to use any ReadProperty, because the check is in BusinessBase. And in the BusinessRule base class we don't have an FieldExists() check.

What's the correct way do go with lazy loaded properties on the one hand and BusinessRules on the other?

Or should I move such validation entirly to the view model?

thanks

Steve

JonnyBee replied on Friday, September 23, 2011

Hi,

In these cases I create the BusinessRule as an inner class inside the BO. This way I will get access to the inner properties/field of the BO, like  FieldManager and can check if the field fieldExists.I would consider these rules as specialized rules for just this BO.

Use snippet cslarule to create the inner rule.

Semantical code to be placed inside the BO:

    private class InnerRule : Csla.Rules.BusinessRule
    {
      public InnerRule(IPropertyInfo primaryProperty)
        : base(primaryProperty)
      { }
 
      protected override void Execute(RuleContext context)
      {
        var myRoot = (Root)context.Target;
        var fm = myRoot.FieldManager;
 
        if (fm.FieldExists(PrimaryProperty))
        {
          // do  the check here 
          var value = (objectType)myRoot.GetProperty(PrimaryProperty);
        }
      }
    }

 

Copyright (c) Marimer LLC