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.