I'm using the following results transformer to try and retrieve less data from a mixed collection of documents. All documents inherit from a base type, but I want to pull back some of the fields from derived types, if present.
Here was my attempt at it (cut down for brevity):
public DocumentAsSearchResultTransformer()
{
TransformResults = docs => from doc in docs
// need several casts to get the properties of the lower cast variables
let subDoc = doc as SubDocumentType
let subDoc2 = doc as SubDocumentType2
select new SearchResult
{
EntityId = doc.EntityId,
Name = doc.Name
// start pulling out document type specific fields
Categories = subDoc != null ? subDocCategories : null,
UserTags = subDoc2 != null ? subDoc2.UserTags : null
};
}
However, when I try and get this results transformer onto the server, I receive the following exception:
System.ServiceModel.ServiceActivationException: The service '/MyService/MyService.svc' cannot be activated due to an exception during compilation. The exception message is: Exception has been thrown by the target of an invocation..
---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> Raven.Abstractions.Exceptions.BadRequestException: Could not understand query: Could not understand query:
[DomRegion FileName=, Begin=(3, 18), End=(-1, -1)]: Error - Unexpected symbol As'
[DomRegion FileName=, Begin=(6, 27), End=(-1, -1)]: Error - Unexpected symbol
As'
[DomRegion FileName=, Begin=(9, 33), End=(-1, -1)]: Error - Unexpected symbol As' ---> System.Net.WebException: The remote server returned an error: (400) Bad Request.
at System.Net.HttpWebRequest.GetResponse()
at Raven.Client.Connection.HttpJsonRequest.ReadJsonInternal(Func
1 getResponse)
--- End of inner exception stack trace ---
at Raven.Client.Connection.HttpJsonRequest.HandleErrors(WebException e)
at Raven.Client.Connection.HttpJsonRequest.ReadJsonInternal(Func1 getResponse)
at Raven.Client.Connection.HttpJsonRequest.ReadResponseJson()
at Raven.Client.Connection.ServerClient.DirectPutTransformer(String name, OperationMetadata operationMetadata, TransformerDefinition definition)
at Raven.Client.Connection.ReplicationInformer.TryOperation[T](Func
2 operation, OperationMetadata operationMetadata, OperationMetadata primaryOperationMetadata, Boolean avoidThrowing, T& result, Boolean& wasTimeout)
at Raven.Client.Connection.ReplicationInformer.ExecuteWithReplication[T](String method, String primaryUrl, OperationCredentials primaryCredentials, Int32 currentRequest, Int32 currentReadStripingBase, Func2 operation)
at Raven.Client.Connection.ServerClient.ExecuteWithReplication[T](String method, Func
2 operation)
at Raven.Client.Indexes.AbstractTransformerCreationTask.Execute(IDatabaseCommands databaseCommands, DocumentConvention documentConvention)
at Raven.Client.Indexes.IndexCreation.CreateIndexes(ExportProvider catalogToGetnIndexingTasksFrom, IDocumentStore documentStore)
at MyService.MyService..ctor() in c:\Users\me\repos\Admin\MyService\MyService.svc.cs:line 51
--- End of inner exception stack trace ---
// more stack trace (probably not needed)
So, it looks like I'm casting wrong. What's the best way of me getting to these derived class properties? Or am I attempting the impossible?
Any help appreciated.
I didn't understand what was meant by trying to use AsDocument and my attempts at using it resulted in ugly code that didn't work, so I gave that up and tried to come up with another idea.
It turns out that the <T> in the AbstractTransformerCreationTask doesn't have to align with the document types in the index, it just gives you an easier time of intellisense.
So, to solve this, I made my transformer class use the SearchResult type as the <T>, as well as being the type I returned.
And I was then able to assign the properties from the documents normally.
Which works great!
I then ran into the problem though that I didn't want some of the bigger properties coming back, but I wanted to compute some values off of them. Which is thankfully easy to solve. If you include those properties you don't want coming back from your search in your SearchResult model, you can then use them in your transform, even if you don't send them back from the transform.
Since you've left the Votes property of your selected SearchResult null, it won't come back from the query. But your computed property will.
Looking at the transform that it makes from this on the server side, it's a pretty neat transform doing it this way, too.
Hope this helps someone else handling a similar situation.