I'm storing objects in RavenDb that all inherit from a base class and I am using a Multi-Map index to search across all subtypes like this:
public class BaseRequest
{
public Guid Id { get; set; }
public string RequestName { get; set; }
public DateTime RequiredDate { get; set; }
}
public class RequestA: BaseRequest
{
public string SomethingForA { get; set; }
}
public class RequestB : BaseRequest
{
public int SomethingForB { get; set; }
}
public class AllRequests: AbstractMultiMapIndexCreationTask
{
public AllRequests()
{
AddMap<RequestA>(requests => from req in requests select new {req.RequestName, req.RequiredDate});
AddMap<RequestB>(requests => from req in requests select new {req.RequestName, req.RequiredDate });
}
}
And I search it like this:
public BaseRequest[] Search(string requestType, string requestName, DateTime? requestDate = null) {
var q = RavenSession.Query<BaseRequest, AllRequests>();
if (!string.IsNullOrEmpty(requestName)) {
q = (IRavenQueryable<BaseRequest>)Queryable.Where(q, x => x.RequestName == requestName);
}
if (requestDate.HasValue) {
q = (IRavenQueryable<BaseRequest>) Queryable.Where(q, x => x.RequiredDate == requestDate);
}
return q.ToArray();
}
What I would like to do is further filter the results by the CLR-Type of the request. Is it possible to do this with the "Raven-Entity-Name" metadata field, and if so how?
I know I could just use Query<RequestA>()
etc but it is likely that I will need to filter by multiple types at a later date and these types will be dynamically chosen by the user.
Note: What I really want to do is use the index to pull back Requests given a certain RequestName, but only return the RequestA's (and later only RequestA, RequestC and RequestDs). I don't want to do multiple queries to get back each type individually, I want to do the one query that queries by the parameters and sometimes type.
The system is being designed so that Requests types will be getting added every month or so and we will probably end up with a couple of hundred different types. I'd like to dynamically search for a set of specific types with given parameters.
Worked it out. I needed to use MetadataFor(req)
to add the clr type to the index and then use a specific map type to query with. Like this:
public class AllRequests: AbstractMultiMapIndexCreationTask
{
public class SearchMap {
public string RequestName{get;set;}
public DateTime RequiredDate{get;set;}
public string RequestType{get;set;}
}
public AllRequests(){
AddMap<RequestA>(requests => from req in requests select new {req.RequestName, req.RequiredDate, RequestType = MetadataFor(req)["Raven-Clr-Type"]});
AddMap<RequestB>(requests => from req in requests select new {req.RequestName, req.RequiredDate, RequestType = MetadataFor(req)["Raven-Clr-Type"] });
}
}
I can then query against actual fields of the Request, and also by type like this:
public BaseRequest[] Search(string requestType, string requestName, DateTime? requestDate = null) {
var q = RavenSession.Query<AllRequests.SearchMap, AllRequests>();
if (!string.IsNullOrEmpty(requestName)) {
q = (IRavenQueryable<BaseRequest>)Queryable.Where(q, x => x.RequestName == requestName);
}
if (requestDate.HasValue) {
q = (IRavenQueryable<BaseRequest>) Queryable.Where(q, x => x.RequiredDate == requestDate);
}
if (!string.IsNullOrEmpty(requestType))
{
q =
q.Where(
x =>
x.RequestType == GetClrTypeFromPassedInValue(requestType));
}
return q.As<BaseRequest>().ToArray();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With