I'm familiar with what AsReadOnly does - it used to be my preferred
approach! Until I realised that compile time errors are preferable to
runtime errors :)

You could argue that a combination of both techniques is best - that way
you're still exposing a readonly interface and preventing the casting
problem. But if my developers are casting back to lists instead of using the
appropriate methods (AddXXX, RemoveXXX), I've got bigger problems. I try to
expose a public interface that makes the wrong things hard and the right
things easy - I rarely go further than that. YMMV.

On Sun, Jan 31, 2010 at 2:27 AM, Hudson Akridge <hudson.akri...@gmail.com>wrote:

> You can make the getter an IEnumerable for your property wrapper, but you
> can still cast it back to a list and then make modifications to it.
> .AsReadOnly() wraps it in a new read only collection that throws exceptions
> whenever .Add/.Remove or any other collection modification methods are
> attempted to be called. Otherwise all you're doing it providing a read only
> interface, but not actually enforcing it.
>
> Example:
> public class Person
>     {
>         public Person()
>         {
>             _test = new List<string>();
>         }
>         private readonly IList<string> _test;
>         public IEnumerable<string> Test
>         {
>             get { return _test; }
>         }
>     }
>
> //Usage
>             var tmp = new Person();
>             var tmp2 = tmp.Test as List<string>;
>             tmp2.Add("test");
>
> tmp2 will have a count of 1 after this, and "test" will have been added.
> This is typically not what you'd want a user of your model to be able to do.
>
> On Fri, Jan 29, 2010 at 11:23 PM, Paul Batum <paul.ba...@gmail.com> wrote:
>
>> Not sure if I'm following entirely, but my approach to exposing
>> collections is to make the getter an IEnumerable:
>>
>> public class Foo
>> {
>>   private List<Bar> _bars { get; set; }
>>
>>   public IEnumerable<Bar> Bars
>>   {
>>     get { return _bars; }
>>   }
>> }
>>
>> Then I map this using an access strategy:
>>
>>  public void Override(AutoMapping<Foo> mapping)
>>      {
>>          mapping.HasMany(x => x.Bars)
>>
>> .Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore)
>>      }
>>
>>
>>
>> On Sat, Jan 30, 2010 at 4:20 AM, TheNephalim 
>> <robert.eberh...@gmail.com>wrote:
>>
>>> I'm definitely going to look into the other strategies that you
>>> mentioned.
>>>
>>> One that I found, and seems to work, is the wrapper strategy that you
>>> alluded to in item number 4.  I created a private property that is
>>> revealed in the mapping and is accessed using the wrapper in a public
>>> property.  When I tested two other properties that I had implemented
>>> in this fashion, NHibernate determined that the collections were not
>>> initialized using the assert that I mentioned in my previous posting
>>> and only generated SQL if I directly accessed the collection directly,
>>> i.e. User.Phones.Count.
>>>
>>> Thank you for your response and confirming what I was thinking as well
>>> as giving me some other avenues to pursue.
>>>
>>> -Robert Eberhart
>>>
>>> On Jan 29, 11:54 am, Hudson Akridge <hudson.akri...@gmail.com> wrote:
>>> > You may want to toss your question over to the NHUsers google group,
>>> but
>>> > I'll give you my feedback for as much as It'll help ;)
>>> >
>>> > is this a trade off wherein we sacrifice encapsulation for performance
>>> >
>>> > This. As far as I'm able to gleen, that is the correct assumption to
>>> make.
>>> > There are ways around this.
>>> > 1.) Don't access the collection unless you absolutely need it
>>> > 2.) Look into doing Join Fetch's during your queries when you get the
>>> data
>>> > back if you know you're going to be using that collection as a result
>>> of the
>>> > query.
>>> > 3.) Look into batch or subselect fetching, this is a good loading
>>> strategy
>>> > imo
>>> > 4.) Look into lazy=extra. This allows you to do counts, contains, and a
>>> few
>>> > other common collection statements without loading the collection. You
>>> will
>>> > still have to access the backing collection, but you can write a
>>> wrapper in
>>> > your model. For example:
>>> > public virtual int FastCountOfLogins()
>>> > {
>>> > return _logins.Count();
>>> >
>>> > }
>>> >
>>> > That will keep your collection lazy loaded until you actually need to
>>> do
>>> > something like a for each and iterate over it.
>>> > 5.) Grab nhprofiler. This is one of the single best tools for finding
>>> bottle
>>> > necks in your application.
>>> >
>>> > On Fri, Jan 29, 2010 at 8:10 AM, TheNephalim <
>>> robert.eberh...@gmail.com>wrote:
>>> >
>>> >
>>> >
>>> > > I have several issues that I'm working on, because I'm a newbie at
>>> > > this, and wanted to address the one that I "solved" first.
>>> >
>>> > > The problem was that I was noticing that all of my collections were
>>> > > not loading lazily, no matter what I did to mark them as such.  It
>>> > > then dawned on me that the problem was the way I was returning the
>>> > > collection.
>>> >
>>> > > For example,
>>> >
>>> > >        public virtual IList<Login> Logins {
>>> > >            get { return new List<Login>(_logins).AsReadOnly(); }
>>> > >            protected set { _logins = value; }
>>> > >        }
>>> >
>>> > > I did it this way because if you just return _logins, you're actually
>>> > > returning a reference to the private variable which violates
>>> > > encapsulation and the whole reason for marking it private in the
>>> first
>>> > > place.
>>> >
>>> > > The problem is that the parent object, User, is a proxy.  Any time
>>> > > that that parent object was accessed, for example, to set
>>> > > User.LastName, a query for each of the collections was fired.  The
>>> > > solution was to change the property to this:
>>> >
>>> > >        public virtual IList<Login> Logins {
>>> > >            get { return _logins; }
>>> > >            protected set { _logins = value; }
>>> > >        }
>>> >
>>> > > I have run several tests in NUnit and watched the queries coming back
>>> > > to know that this is what's happening.  Additionally, I used the
>>> > > following:
>>> >
>>> > >        Assert.IsFalse(NHibernateUtil.IsInitialized(testUser.Logins));
>>> >
>>> > > It passes for the second property implementation and not the first.
>>> >
>>> > > The question I have is this:  Is there a way to encapsulate the
>>> > > private variable but still have a proxy for lazy loading, or is this
>>> a
>>> > > trade off wherein we sacrifice encapsulation for performance?
>>> >
>>> > > Any help you can offer is appreciated.
>>> >
>>> > > Sincerely,
>>> > > Robert Eberhart
>>> >
>>> > > --
>>> > > You received this message because you are subscribed to the Google
>>> Groups
>>> > > "Fluent NHibernate" group.
>>> > > To post to this group, send email to
>>> fluent-nhibern...@googlegroups.com.
>>> > > To unsubscribe from this group, send email to
>>> > > fluent-nhibernate+unsubscr...@googlegroups.com<fluent-nhibernate%2bunsubscr...@googlegroups.com>
>>> <fluent-nhibernate%2bunsubscr...@googlegroups.com<fluent-nhibernate%252bunsubscr...@googlegroups.com>
>>> >
>>> > > .
>>> > > For more options, visit this group at
>>> > >http://groups.google.com/group/fluent-nhibernate?hl=en.
>>> >
>>> > --
>>> > - Hudsonhttp://www.bestguesstheory.comhttp://twitter.com/HudsonAkridge
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "Fluent NHibernate" group.
>>> To post to this group, send email to fluent-nhibern...@googlegroups.com.
>>> To unsubscribe from this group, send email to
>>> fluent-nhibernate+unsubscr...@googlegroups.com<fluent-nhibernate%2bunsubscr...@googlegroups.com>
>>> .
>>> For more options, visit this group at
>>> http://groups.google.com/group/fluent-nhibernate?hl=en.
>>>
>>>
>>  --
>> You received this message because you are subscribed to the Google Groups
>> "Fluent NHibernate" group.
>> To post to this group, send email to fluent-nhibern...@googlegroups.com.
>> To unsubscribe from this group, send email to
>> fluent-nhibernate+unsubscr...@googlegroups.com<fluent-nhibernate%2bunsubscr...@googlegroups.com>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/fluent-nhibernate?hl=en.
>>
>
>
>
> --
> - Hudson
> http://www.bestguesstheory.com
> http://twitter.com/HudsonAkridge
>
> --
> You received this message because you are subscribed to the Google Groups
> "Fluent NHibernate" group.
> To post to this group, send email to fluent-nhibern...@googlegroups.com.
> To unsubscribe from this group, send email to
> fluent-nhibernate+unsubscr...@googlegroups.com<fluent-nhibernate%2bunsubscr...@googlegroups.com>
> .
> For more options, visit this group at
> http://groups.google.com/group/fluent-nhibernate?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Fluent NHibernate" group.
To post to this group, send email to fluent-nhibern...@googlegroups.com.
To unsubscribe from this group, send email to 
fluent-nhibernate+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/fluent-nhibernate?hl=en.

Reply via email to