Mike Moore
Mike Moore

Reputation: 1340

How to make Raven DB Lucene query work with result transformer

I have a RavenDB Linq query that uses a result transformer working properly that I am attempting to convert to Lucene syntax in order to facilitate creating dynamic queries. However, I am unable to get the Lucene query to work correctly and am looking for some guidance.

Result Transformer:

public class CallRecordWithDisplayNameTransformer : AbstractTransformerCreationTask<CallRecord>
{
  public CallRecordWithDisplayNameTransformer()
  {
    TransformResults = callRecords => from callRecord in callRecords
      let displayNameRecord = LoadDocument<DisplayName>(callRecord.PhoneNumber)
      let displayName = (displayNameRecord != null) ? displayNameRecord.Name : string.Empty
      select new{
        CallRecord = callRecord,
        DisplayName = displayName
      };
  }
}

The result class that is created by the transformer:

public class CallRecordWithDisplayName
{
  public CallRecord CallRecord { get; set; }
  public string DisplayName { get; set; }
}

Here is the Linq query that works successfully (when this query is executed 25 of the fully populated & transformed 'CallRecordWithDisplayName' objects are returned):

session.Query<CallRecord>()
    .Customize(x => x.WaitForNonStaleResults(TimeSpan.FromSeconds(5)))
    .OrderByDescending(c => c.CallDateTime)
    .TransformWith<CallRecordWithDisplayNameTransformer, CallRecordWithDisplayName>()
    .Skip(0)
    .Take(25)
    .ToList();

Here is the Lucene query that does not work correctly. When this query is executed it returns 25 null instances of 'CallRecord' objects, not the 'CallRecordWithDisplayName' objects that are created by the transformer.

session.Advanced.LuceneQuery<CallRecord>()
  .OrderByDescending("CallDateTime")
  .Skip(0)
  .Take(25)
  .SetResultTransformer(new CallRecordWithDisplayNameTransformer().TransformerName)
  .ToList();

Here are the server logs that show the queries that are being sent to the server for the Linq (request #584) and Lucene (request #585) requests:

Request # 584: GET     -     7 ms - FiddleFlights - 200 - /indexes/dynamic/CallR
ecords?&pageSize=25&sort=-CallDateTime&resultsTransformer=CallRecordWithDisplayN
ameTransformer&operationHeadersHash=525986370
        Query:
        Time: 6 ms
        Index: Auto/xz2MTg77IKTTb7MyHLD/4A==
        Results: 25 returned out of 597 total.

Request # 585: GET     -     7 ms - FiddleFlights - 200 - /indexes/dynamic/CallR
ecords?&pageSize=25&sort=-CallDateTime&resultsTransformer=CallRecordWithDisplayN
ameTransformer
        Query:
        Time: 5 ms
        Index: Auto/xz2MTg77IKTTb7MyHLD/4A==
        Results: 25 returned out of 597 total.

Upvotes: 0

Views: 429

Answers (1)

Jens Pettersson
Jens Pettersson

Reputation: 1177

Try creating a static index of your CallRecords and call it like this:

session.Advanced.LuceneQuery<CustomerNameViewModel, Customers_ByName>()
    .OrderByDescending("Name")
    .Skip(0)
    .Take(25)
    .SetResultTransformer(new CustomerNameTransformer().TransformerName)
    .ToList();

Edit: Or use the Auto index like this:

session.Advanced.LuceneQuery<CustomerNameViewModel>("Auto/Customers/ByName")

Where Customer in my case is your CallRecord.

This works for me in RavenDB 3.0.3599, however, if you're using 3.0 you should use DocumentQuery<> instead of LuceneQuery as the latter is obsolete (but it works).

However, I'm not sure this is the "correct" way to do it, but I can't find another way of defining the return type of the Transformer when used with .SetResultTransformer(...)

Hope this helps!

Edit: Here's my transformer, built with weird LoadDocument just to test. so it doesn't make any "real" sense:

public class CustomerNameTransformer : AbstractTransformerCreationTask<Customer>
{
    public CustomerNameTransformer()
    {
        TransformResults = results => from customer in results
                                      let fixture = LoadDocument<Fixture>(customer.FixtureNumber)
                                      select new CustomerNameViewModel
                                      {
                                          Id = customer.Id,
                                          Name = customer.Name,
                                          FixtureNumber = fixture.FixtureNumber,
                                          Customer = customer
                                      };
    }
}

Upvotes: 1

Related Questions