Properties and RelationshipTypes

Properties and RelationshipTypes

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


acgritt posted on Thursday, June 04, 2009

In looking to implement some LazyLoaded properties for our Silverlight application, I have noticed that the RegisterProperty method takes an enum named RelationshipTypes that has Child and LazyLoad as its values.  However, after looking through the 2008 Business Objects book and the web I haven't been able to find much information about exactly what this setting does, if anything.  I know from looking at the code the LazyLoad value has to do with when you call ReadProperty and it returning a value vs an exception.  Can anyone shed more light on this for me so I know if I need to be setting this value or not.

Adam Gritt

RockfordLhotka replied on Thursday, June 04, 2009

This was added after the book.

The LazyLoad option causes CSLA to throw an exception if you attempt to GetProperyt() or ReadProperty() before you load the property with a value. It is a debugging tool to help you avoid accidental bugs where you use a lazy loaded property, get a null, and think that's the right value.

The Child option (and remember these are a bit flag set, so you can have more than one at a time) is not currently used by CSLA .NET. I suppose I broke my own rule by adding a feature that isn't actually used, but it was my way of ensuring I got the bit flag code correct.

acgritt replied on Friday, June 05, 2009

In that case what is the correct way to Lazy Load a property?  According to the code by Sergey in this post: http://forums.lhotka.net/forums/thread/32438.aspx, he uses FieldManager.FieldExists and ReadProperty to check to see if it needs to be loaded.  This would conflict with using the LazyLoad option because then the code would throw an exception.

RockfordLhotka replied on Friday, June 05, 2009

The idea is that you would just use FieldExists().

 

Or to put it another way, the presupposition is that a child reference should never actually be null, so the field either exists or not, and if it doesn’t exist then it must need loading.

 

The technique shown in that other thread remains perfectly valid – it just requires vigilance elsewhere in your code because you could get a null from ReadProperty() and not realize you really had an invalid value. This caused at least a couple people some serious heartburn, which is why this new stricter technique is now available.

 

Rocky

acgritt replied on Friday, June 19, 2009

In using the RelationshipTypes I have code like the following now:

        private bool _loadingChannels = false;
        private static PropertyInfo<Channels.ChannelList> ChannelsProperty = RegisterProperty<Channels.ChannelList>(p => p.Channels, "Channels", RelationshipTypes.LazyLoad);
        public Channels.ChannelList Channels
        {
            get
            {
                if (!_loadingChannels && !FieldManager.FieldExists(ChannelsProperty))
                {
#if SILVERLIGHT
                    _loadingChannels = true;
                    Controllers.Channels.ChannelList.GetChannelList(ReadProperty(IdProperty), (o, e) =>
                        {
                            LoadProperty(ChannelsProperty, e.Object);
                            OnPropertyChanged(ChannelsProperty.Name);
                            _loadingChannels = false;
                        });
#else
                    LoadProperty(ChannelsProperty, Controllers.Channels.ChannelList.GetChannelList(ReadProperty(IdProperty)));
#endif
                }

                return GetProperty(ChannelsProperty);
            }
        }

The problem I am having is that in Silverlight when this code gets called, the first time through it will throw an InvalidOperationException with the message "Property get not allowed." when it calls GetProperty at the end.  In this case should I not be setting it as LazyLoad or is there something else I have wrong here?

Adam Gritt

RockfordLhotka replied on Friday, June 19, 2009

There are two modes.

 

If you use LazyLoad, then you will get an exception on ReadProperty() or GetProperty() until the value has been initialized, and so you need to make sure that doesn’t happen. Arguably this is the “better” approach because it avoids certain bugs you might have in your code.

 

Or don’t use LazyLoad, and realize that ReadProperty() and GetProperty() may return null, even though the REAL value is not null. This is the bug the relationship type helps you avoid – but if you aren’t worried about this case, then you don’t need the new feature.

 

Rocky

 

bniemyjski replied on Friday, October 30, 2009

Hello,

I have the following code:

Account account = profile2.Accounts.AddNew();

which calls this:

private static readonly PropertyInfo< AccountList > _accountsProperty = RegisterProperty<AccountList>(p => p.Accounts, Csla.RelationshipTypes.Child | Csla.RelationshipTypes.LazyLoad);
        private readonly AccountList _accounts = _accountsProperty.DefaultValue;
        public AccountList Accounts
        {
            get
            {
                if(!FieldManager.FieldExists(_accountsProperty))
                {
                    if(this.IsNew)
                        LoadProperty(_accountsProperty, AccountList.NewList());
                    else
                        LoadProperty(_accountsProperty, AccountList.GetByUniqueID(UniqueID));
                }

                return GetProperty(_accountsProperty, _accounts);
            }
        }

The property is lazy loaded and is a child property. If I change the order of the RelationshipTypes then the FeildManager might not work correctly. What is the best approach for this scenario?

Thanks
-Blake Niemyjski

RockfordLhotka replied on Friday, October 30, 2009

What do you mean by "change the order"? I don't understand.

bniemyjski replied on Monday, November 02, 2009

Hello,

I mean if I change the following from:

p => p.Accounts, Csla.RelationshipTypes.Child | Csla.RelationshipTypes.LazyLoad);

to:

p => p.Accounts, Csla.RelationshipTypes.LazyLoad | Csla.RelationshipTypes.Child );

It behaves differently.

Thanks
-Blake Niemyjski

RockfordLhotka replied on Monday, November 02, 2009

That makes no sense. These are bit mask flags, so either way you write that line of code the numeric result is 3.

 

Child = 1, LazyLoad = 2. Combine those values and you get a 3, regardless of the order in which they are combined.

 

      Console.WriteLine((int)Csla.RelationshipTypes.LazyLoad);

      Console.WriteLine((int)Csla.RelationshipTypes.Child);

      Console.WriteLine((int)(Csla.RelationshipTypes.Child | Csla.RelationshipTypes.LazyLoad));

      Console.WriteLine(((Csla.RelationshipTypes.Child | Csla.RelationshipTypes.LazyLoad) & Csla.RelationshipTypes.LazyLoad) != 0);

      Console.WriteLine((int)(Csla.RelationshipTypes.LazyLoad | Csla.RelationshipTypes.Child));

      Console.WriteLine(((Csla.RelationshipTypes.LazyLoad | Csla.RelationshipTypes.Child) & Csla.RelationshipTypes.LazyLoad) != 0);

      Console.ReadLine();

 

Additionally, the framework never uses the Child value for anything – it is just there as a placeholder. Only the LazyLoad value is actually used in the ReadProperty() method of BusinessBase – nowhere else.

 

Exactly what behavior are you seeing that is different? Different behavior in ReadProperty()?

 

RockfordLhotka replied on Monday, November 02, 2009

You know, I just looked a little more closely at your code, and it is kind of messed up.

You are using a combination of private backing field and managed backing field techniques. No wonder it isn't working like you'd expect.

With child objects I recommend using a managed backing field - in which case you should not be declaring or using a private backing field to store the reference.

bniemyjski replied on Monday, November 02, 2009

Hello,

Thanks for the tip.

Thanks
-Blake Niemyjski

tiago replied on Friday, December 23, 2011

RockfordLhotka

The Child option (...) is not currently used by CSLA .NET. I suppose I broke my own rule by adding a feature that isn't actually used, but it was my way of ensuring I got the bit flag code correct.

I noticed PTracker and Using Csla 4 samples don't use the Child option.

This post refers to CSLA 3.5 or 3.6. I had a look at current source code (4.2.2) and found no use of

RelationshipTypes.Child

Is there a planned use? Can we remove it from our source code?

 

 

Copyright (c) Marimer LLC