4

I load types dynamically through reflection, instantiate the classes, fill them with data and then save them to RavenDB. They all implement an interface IEntity.

In the RavenDB UI, I can see the classes correctly displayed and the meta data has the correct CLR type.

Now I want to get the data back out, change it and then save it.

What I'd like to do

I have the System.Type that matches the entity in RavenDB's CLR meta data, assuming that's called myType, I would like to do this:

session.Query(myType).ToList(); // session is IDocumentSession

But you can't do that, as RavenDB queries like so:

session.Query<T>();

I don't have the generic type T at compile time, I'm loading that dynamically.

Solution 1 - the Big Document

The first way I tried (for a proof of concept) was to wrap all the entities in a single data object and save that:

public class Data {
    List<IEntity> Entities = new List<IEntity>();
}

Assuming the session is opened/closed properly and that I have an id:

var myDataObject = session.Load<Data>(Id);

myDataObject.Entities.First(); // or whatever query 

As my types are all dynamic, specified in a dynamically loaded DLL, I need my custom json deserializer to perform the object creation. I specify that in the answer here.

I would rather not do this as loading the entire document in production would not be efficient.

## Possible solution 2 ##

I understand that Lucene can be used to query the type meta data and get the data out as a dynamic type. I can then do a horrible cast and make the changes.


Update after @Tung-Chau

Thank you to Tung, unfortunately neither of the solutions work. Let me explain why:

I am storing the entities with:

session.Store(myDataObject);

In the database, that will produce a document with the name of myDataObject.GetType().Name. If you do:

var myDataObject = session.Load<IEntity>(Id);

Then it won't find the document because it is not saved with the name IEntity, it is saved with the name of the dynamic type.

Now the Lucene solution doesn't work either but for a slightly more complex reason. When Lucene finds the type (which it does), Raven passes it to the custom JsonDeserialiser I mentioned. The custom Json Deserialiser does not have access to the meta data, so it does not know which type to reflect.

Is there a better way to retrieve data when you know the type but not at compile time?

Thank you.

Community
  • 1
  • 1
Dr Rob Lang
  • 6,659
  • 5
  • 40
  • 60

1 Answers1

2

If you have an ID (or IDs):

var myDataObject = session.Load<IEntity>(Id);
//change myDataObject. Use myDataObject.GetType() as you want 
//....
session.SaveChange();

For query, LuceneQuery is suitable

var tag = documentStore.Conventions.GetTypeTagName(typeof(YourDataType));
var myDataObjects = session.Advanced
                 .LuceneQuery<IEntity, RavenDocumentsByEntityName>()
                 .WhereEquals("Tag", tag)
                 .AndAlso()
                  //....
Tung Chau
  • 113
  • 6
  • Thank you for your answer, Tung. Unfortunately, neither solution works. I've updated my post because the reasons are more complex than a comment will allow. – Dr Rob Lang Nov 07 '13 at 17:28