Properties and RelationshipTypesProperties 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 NiemyjskiRockfordLhotka 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 Niemyjskitiago 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