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); } } } }); }