The other day, Lane (sits in same little office as me, sometimes works together with me) asked how to find all the clients with at least one active plan:

image image

He had written some code that did the filtering in code (i.e., get got a list of all plans, then accumulated a distinct list of clients for the plans that were active.) This code didn't work for a completely unrelated reason. We fixed that problem and left it at that. This was a good problem for me to play with to learn more about projections and subqueries in NHibernate, so I took the problem home with me. This stuff confuses me and seems to be rather poorly documented: there is a section of the NH documentation that touches on this functionality but doesn't really explain what a projection is, or any other background info.

So, my menal definition of a projection is, you build an NH query then get something else about the set of objects your query defines, such as aggregate information.

Of course, there is also this post from Oren, which has lots of clues and a good description of his sample (I find the NH documentation samples kind of hard to follow sometimes,) but his solution only works on the "trunk" (circa Nov. 2006). I can't find where the "Expression.Property" is implemented in 1.2GA NH.

So for the clients-with-active-plans problem, My first thought was, "Let's just group the active plans by client, and project the clients":

IList<Client> clientsWithActivePlans = 
      session.CreateCriteria(typeof(Plan))
            .SetProjection(Projections.ProjectionList()
            .Add(Projections.Property("Client"))
            .Add(Projections.GroupProperty("Client")))
            .Add(Expression.Eq("IsActive", true))
            .List<Client>();

This results in:

image

I am expecting a list of 3 clients: I have 5 clients in the database, one with no plans, one with plans but none active, the rest with active plans.

"from" does have 3 entries, but why does each row have 2 objects in it? I was expecting just the Client object. Here is the SQL:

SELECT 
   this_.ClientID as y0_, 
   this_.ClientID as y1_ 
FROM 
   [Plan] this_ 
WHERE 
   this_.IsActive = @p0 
GROUP BY 
   this_.ClientID; 

@p0 = 'True'

Not sure why ClientID is selected twice...what if I remove the Property projection...does group by get me the grouping column/object automatically?

IList<Client> clientsWithActivePlans = 
session.CreateCriteria(typeof(Plan))
            .SetProjection(Projections.GroupProperty("Client"))
            .Add(Expression.Eq("IsActive", true))
            .List<Client>();

Yields this SQL:

SELECT 
   this_.ClientID as y0_ 
FROM 
   [Plan] this_ 
WHERE 
   this_.IsActive = @p0 
GROUP BY 
   this_.ClientID; @p0 = 'True'

This looks better...but it only fetches the IDs. The Clients are then lazy loaded if you iterate over them:

Console.WriteLine("Clients with active Plans:");
foreach (Client client in clientsWithActivePlans)
   Console.WriteLine(client.Name);

Generates:

SELECT 
   client0_.ID as ID0_0_, 
   client0_.Name as Name0_0_ 
FROM 
   Client client0_ 
WHERE 
   client0_.ID=@p0; 

@p0 = '2'

For each Client in the list.

How about making this query into a detached criteria, and fetching full Clients where the Client exists in the above query (i.e., use the above query as a subquery.)

DetachedCriteria clientIDsWithActivePlans =
 DetachedCriteria.For<Plan>()
      .SetProjection(Projections.ProjectionList()
      .Add(Projections.GroupProperty("Client")))
      .Add(Expression.Eq("IsActive", true));

IList<Client> clientsWithActivePlans = session.CreateCriteria(typeof(Client))
      .Add(Subqueries.PropertyIn("ID", clientIDsWithActivePlans))
      .List<Client>();

Gives me one query to the database:

SELECT 
   this_.ID as ID0_0_, 
   this_.Name as Name0_0_ 
FROM 
   Client this_ 
WHERE 
   this_.ID in (
      SELECT this_0_.ClientID as y0_ 
      FROM [Plan] this_0_ 
      WHERE this_0_.IsActive = @p0 
      GROUP BY this_0_.ClientID); 

@p0 = 'True'

and no lazy loading the clients as we iterate over the list.

I think I've only just scratched the surface with what you could do with Projections and Subquery criterions in NHibernate. I hope Oren posts more about this and I hope I have more time to play around with this on my own to get a better handle on how it works.


 
Categories: database | nhibernate

December 1, 2006
@ 06:17 AM

Long time since I last posted. Need less to say, I have been a little busy. I hope to resume most of my regular life soon, but here are a few highlights (to be followed with further posts later) of what I've been up to:

  • Julie and Allie came back from a month long trip to Taiwan, to visit Julie's mom. Allie got her second hair cut - the last was when she was 1. She went from waste length hair to just past the shoulders. She made amazing progress in Chinese. Before this trip, she had a bad accent and very limited vocabulary. Hanging around with two cousins she adores, as well as dozens of other extended family members willing to spend time doing things with and talking to her made a huge difference.
  • At the beginning of November, I was invited to participate in a week long training session my company puts on - not for developers, but for analysts. It was a really neat experience and I think it speaks highly of our management - that they get the need to keep developers as up to speed as anyone else on how the business works. I learned a ton of stuff, and go to spend time with top minds in the industry (and bug them with questions.) In addition, I met a bunch of cool people from our offices all over the world. We have a lot of work to do on the technology front to improve our organization, but I have now doubt that we're going to do it. This company will grow amazingly over the coming years, and I am glad to be here to take part in that.
  • We were going to go to our friends Monique and Dominique's house, in Portland, for Thanksgiving, but ended up inviting a few people over. More people got invited. Then a few more. In the end, I think 19 people showed up. We had a blast, but it was a lot of work to get ready and clean up.

Enough personal stuff...

  • I enjoyed the final day of the Seattle Code Camp. I got a chance to talk to two of my agile heroes, Brad Wilson, and Peter Provost. I also got to talk to Stuart Celarier, and was introduced to the Seattle XP Group. Too bad their meetings are the same day as South Sound .NET - which I haven't gone to either in several months. Argg...
  • Speaking of user groups: Some co-workers finally got me excited enough to form an in house Developers Group. I had the good fortune of getting to know someone in our company that is one of those "do-er" kinds of people - the kind that can organize a teleconference on 3 continents with 100 people, in under an hour, without batting an eye. I kind of bashfully asked if there was any way we could use one of our company's fancier meeting/conference rooms after hours for around 20 people. She basically said, "Go for it!" and I found that it was actually as easy as inviting the room to our conference. I could even invite coffee and his friends pizza and sandwiches from the cafeteria downstairs if my boss was willing to pay for them (hmm...haven't asked about that...) We got a sweet conference room on the twelfth floor, with an awesome view of the Puget sound, a massive projector and computer, fancy mood lighting, comfy chairs, a mezzanine level - the whole nine yards. I hope about 10 people will show up, which we will try to grow to 20 or 30 as time passes. Thanks Wei, Michael, and Ariel for finally pushing me over the edge on this!
  • I've been learning SSIS. It's been kind of frustrating, kind of fun. Mostly, it's only fun when it works. It was really painful to get to the "works" stage with my first couple of projects, but aside from a few gripes, I see how powerful and useful it could be going forward.
  • Our development team at work feels like it's getting tighter. Inspired by Brad and Peter, we spent more energy trying to do pair programming and share code better. I think we are good, but we could be a lot better. We only have one project we are doing right now that is truly owned by all developers on the team. The other 4 projects we actively work on all have code owners, and we are working to abolish that.
  • My boss said I was a "hippy coder" at a recent team meeting held down the street, in an...umm...off site meeting facility with fermented beverages. I was a little shocked. I try to be open minded, but compared to most of the other developers in our organization, I think I am _more_ disciplined - I use TDD, automated builds, normalized database schemas, consistent names, etc., in comparison with the local standard, which is to say "good enough" a lot. I guess I was just kind of shocked about this, but my boss has a history of making startling observations about me, which give me great cause for self reflection - which is a good thing.
  • I installed Vista...like it...not the stuff of dreams, but lots of little things I like (parental controls especially.)
  • I finally checked out the "Baroque Cycle" from the local library. What a read. Lots of history. Lots of math and science. Heavy. Sucked up a lot of time.
  • I have been working on something kind of neat, integrating SQL Server, our applications, and OLAP. For a taste, here's a paper a colleague wrote several years ago, about doing almost the same thing, just using SAS for the application part (where I would be using .NET.)

Anyway, I hope to blog more now. Later!


 
Categories: agile | career | CodeCamp | database | tdd | ug

September 27, 2006
@ 12:37 PM

 For several years I have been wondering if something like what is described in this article will happen. Why do big relational databases have such a tight grip on business software architecture?

One of the most dramatic changes in the enterprise software market is coming to a database near you. This revolution heralds a shift to a mix of options that include open source databases, in-memory databases, and turnkey database/hardware bundles, among others.

Another thing not mentioned in the article is the rise in popularity of "in-process" databases: Oracle buying Sleepy Cat, Microsoft's SQL Everywhere, etc. I think there is a big gap for things like this - when you still need something like reporting but don't need a huge database with it's installation and licensing hassles.

Source: The Coming Database Revolution
Originally published on Wed, 27 Sep 2006 11:43:07 GMT


 
Categories: database

September 25, 2006
@ 05:26 AM

Exciting! For Me: Now I don't need to use my own SQL Everywhere dialect, and I can use NHibernate with legacy systems that require me to use stored procs. I like built-in generics support too - remembering to add Ayende's NHibernate.Generics was just one more thing to remember. Can't wait till this is done with beta.

Source: NHibernate 1.2 Beta1 Released!
Originally published on Mon, 25 Sep 2006 12:32:06 GMT


 
Categories: database | library | tool

September 13, 2006
@ 04:41 PM

I was looking for answers to my sql/e question today (still nothing) and found the team blog for the sql/e team. One cool bit I found there was the "|DataDirectory|" syntax (scroll down a bit) for specifying the location of your data file. I don't know how (if?) I would have ever found that in the documentation. MSDN Blogs rule.


 
Categories: database | sqle

August 29, 2006
@ 08:42 PM
I mentioned in a previous post that I was going to investigate using SQL Server Everywhere edition for a database to unit test against, when the database really can't be removed from the picture.

Since then I have been swamped with work, and have not had time to post.

I did end up using SQL Everywhere for unit tests on a project. I had to copy-past-edit some code from the NHibernate Sql2000 family of driver classes, but it was pretty easy and I only had to open the sqle documentation once (...to find out that they don't support TOP.)

I will try to post more details later, but it was basically the same as my previous post on SQLite - I didn't notice any performance differences, nor does it support lots of functionality that SQLite doesn't, but it is SQL Server's little brother and it can replicate with SQL Server (very exciting!), which is a feature I plan on using for something else soon.

Anyway, just wanted to post something...


 
Categories: database | tdd | sqle

A short description of how I use SQLite to do unit tests that want data access.
 
Categories: article | database | sqle | tdd

Yesterday afternoon, I was talking with one of my co-workers, Michael. I was yammering on about how much I liked SQLite for unit testing and how much faster in-process databases engines were for applications that didn't need all the features of relational databases.

Then he mentioned SQL Server Everywhere Edition. It's in process, light weight (the same configuration as what runs on Windows Mobile), and free to distribute. I don't think it supports views or stored procs (installing it now, so I might edit this later) but I avoid those types of database dependencies anyway.

SQL Server Everywhere Edition sounds exciting for a number of reasons.


 
Categories: database | sqle