+3  A: 

NHibernate has the load operation (as opposed to doing a get) exactly for this reason.

session.Save(
  new Comment
      {
         Text = commentTextFromScreen,
         User = session.Load<User>(userID),
         Product = session.Load<Product>(productID)
      }
};

In the above example, you are telling NHibernate: I know these already exist in the database, so don't bother selecting them right now. NHibernate will return proxy objects for them and a select won't happen against the database as long as you don't attempt to access any properties on the objects.

For more info check out Ayende's blog post: The difference between Get, Load, and query by id.

Daniel Auger
That's great! Thanks. I'm wondering how I didn't notice this before :0
UpTheCreek
More generally (in other scenarios), lazy loading and caching will help prevent fetching excess data from the database. Prefer these techniques over exposing id's to the app-at-large.
apollodude217