private static void ExtractContracts <TEntity, TContract>(ISessionWrapper session, ZipArchive zip,
                                                                  Func <QueryOverProjectionBuilder <TEntity>, QueryOverProjectionBuilder <TEntity> > fieldBuilder)
            where TEntity : class
            where TContract : class
        {
            var records = session.QueryOver <TEntity>()
                          .SelectList(fieldBuilder)
                          .List <object[]>();
            var jsonSerializer = new JsonSerializer
            {
                Formatting        = Formatting.Indented,
                NullValueHandling = NullValueHandling.Include
            };
            var zipLock = new object();

            // We should be able to get a bit of a perf boost using parallelism. However, since we're locking on
            // writing to the zip archive, using any more than 2 threads would be pointless in this case
            Parallel.ForEach(records, new ParallelOptions {
                MaxDegreeOfParallelism = 2
            }, record =>
            {
                string zipEntryName   = record[0].ToString();
                int contractLen       = (int)record[1];
                byte[] contractBinary = (byte[])record[2];

                if (contractLen > 0 && contractBinary != null)
                {
                    TContract contract = CompressionHelper.DeserializeObject <TContract>(contractBinary, contractLen);

                    lock (zipLock)
                    {
                        ZipArchiveEntry archiveEntry = zip.CreateEntry(zipEntryName, CompressionLevel.Optimal);

                        using (StreamWriter writer = new StreamWriter(archiveEntry.Open(), Encoding.UTF8))
                        {
                            jsonSerializer.Serialize(writer, contract);
                        }
                    }
                }
            });
        }