I'm intrigued about lazy=extra but tried to research it and couldn't find any information. If I'm correct, HasMany, HasManyToMany, etc. don't have SetAttribute like earlier versions of FNH. Do you have any links you could point me to?

On Feb 1, 2010, at 8:17 PM, Hudson Akridge <[email protected]> wrote:

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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]>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 <[email protected]> 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 <[email protected]>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 <[email protected]> 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 <
> > >>> [email protected]>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
> > >>> [email protected].
> > >>> > > To unsubscribe from this group, send email to
> > >>> > > [email protected]<fluent- nhibernate%[email protected]> > > >>> <fluent-nhibernate%[email protected]<fluent- nhibernate%[email protected]>
> >
> > >>> > > .
> > >>> > > 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 [email protected] .
> > >>> To unsubscribe from this group, send email to
> > >>> [email protected]<fluent- nhibernate%[email protected]>
> > >>> .
> > >>> 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 [email protected] .
> > >> To unsubscribe from this group, send email to
> > >> [email protected]<fluent- nhibernate%[email protected]>
> > >> .
> > >> 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 [email protected] .
> > > To unsubscribe from this group, send email to
> > > [email protected]<fluent- nhibernate%[email protected]>
> > > .
> > > 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 [email protected] . > To unsubscribe from this group, send email to [email protected] . > 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 [email protected] . To unsubscribe from this group, send email to [email protected] . 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 [email protected] . To unsubscribe from this group, send email to [email protected] . 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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/fluent-nhibernate?hl=en.

Reply via email to