Your thoughts on why to just expose it out as an ienumerable make sense. There's positives and negatives to both. Wrapping it in a ReadOnlyCollection initializes it, as well as prevents you from ever being able to take advantage of lazy=extra.
On Mon, Feb 1, 2010 at 6:37 PM, Paul Batum <paul.ba...@gmail.com> wrote: > Yes, sorry, there was an error in my code. You can map the member as > either a field or a property, but you have to use the appropriate > access mechanism. ReadOnlyPropertyThroughCamelCaseField tells > NHibernate to use the mapped property when getting the value, and to > look for a field with camel case naming and to use that when setting > the value. If the underlying member is an autoproperty, then it will > fail to find a matching field. > > > On Tue, Feb 2, 2010 at 8:17 AM, TheNephalim <robert.eberh...@gmail.com> > wrote: > > > > I implemented what Paul suggested, although I had to do it slightly > > differently and I'm not sure why. > > > > public class User { > > > > private IList<Phone> _phones; > > > > /// <summary> > > /// A list of contact phone numbers. > > /// </summary> > > public virtual IEnumerable<Phone> Phones { > > get { return _phones; } > > } > > > > public virtual void AddPhone(Phone phone) { > > Check.Require(phone != null, "Phone cannot be left > > undefined."); > > > > if (!_phones.Contains(phone)) { > > _phones.Add(phone); > > } > > } > > } > > > > The mapping for the property is: > > > > HasMany<Phone>(x => x.Phones) > > .Access.ReadOnlyPropertyThroughCamelCaseField > > (Prefix.Underscore) > > .Table("Phone") > > .KeyColumn("UserId") > > .Cascade.All().Inverse() > > .AsBag(); > > > > If I added the get/set to the private IList<Phone> _phones, I received > > an error indicating that it couldn't find the field "_phones". > > However, now that I'm thinking about it, that might make sense because > > having the get/set would indicate a propert and not a field. I'm not > > sure if the the Property access strategy would work and I believe that > > you would also have to use the Reveal.Property<Entity>("Property") > > method. I also think that you would probably have to rename the > > property to something like m_Phones. I have not have too much luck > > using the Reveal.Property method; sometimes it seems to work and other > > times....not. > > > > I also had to change the List<T> to IList<T>, otherwise to access > > contains I would have to access it through the public IEnumerable > > Phones instead of the private variable. To add a new value, I would > > need to access the private variable, but would receive an error > > indicating an index out of range exception. Changing the collection > > from List<T> to IList<T> seems to have remedied that problem. > > > > I'm going to continue testing to make sure that everything is cool. > > It appears, though, that I have reached something that I can > > definitely live with. > > > > Thanks again, > > Robert > > > > On Jan 30, 6:53 pm, Paul Batum <paul.ba...@gmail.com> wrote: > > > 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> > > > > > >>> <fluent-nhibernate%2bunsubscr...@googlegroups.com<fluent-nhibernate%252bunsubscr...@googlegroups.com> > <fluent-nhibernate%252bunsubscr...@googlegroups.com<fluent-nhibernate%25252bunsubscr...@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> > <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. > > > > > > >> -- > > > >> 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. > > > > > > > -- > > > > - 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> > <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. > > > > -- > > 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. For more options, visit this group at http://groups.google.com/group/fluent-nhibernate?hl=en.