I think I'm streching the use of 'live projections' a little bit.
This will be a long post, so please read carefully. I have submitted a
pull request onto it. So you can test it on your side.
Back to the StackOverFlow types, I decided to have rich Domain objects
and light persistence objects, like this:
Rich Domain objects: hold references to other objects
====================
public class AnswerEntity
{
public string Id { get; set; }
public string UserId { get; set; }
public Question Question { get; set; }
public string Content { get; set; }
}
public class AnswerVoteEntity
{
public string Id { get; set; }
public string QuestionId { get; set; }
public AnswerEntity Answer { get; set; }
public int Delta { get; set; }
}
Light persistence objects: used as denormalized references
==========================
public class Question
{
public string Id { get; set; }
public string UserId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
public class Answer
{
public string Id { get; set; }
public string UserId { get; set; }
public string QuestionId { get; set; }
public string Content { get; set; }
}
public class AnswerVote
{
public string QuestionId { get; set; }
public string AnswerId { get; set; }
public int Delta { get; set; }
}
The main reason for this separation, is that I don't want to "store"
large object graphs in a single document.
So when I insert the rich objects, I simply *Map* them to their light
counterparts ... and store .
Where is the problem?
========================
The problem is in the limitations of the live-projection as it can
load only a "stored" type....
TransformResults = (database, results) =>
from result in results
// this won't work because
'AnswerEntity' is not the stored type, its 'Answer' type
let answer =
database.Load<AnswerEntity>(result.AnswerId)
// Should be like this
//let answer =database.Load<Answer,
Answers_ByAnswerEntity>(result.AnswerId)
// .As<AnswerEntity>();
select new //
AnswerVoteEntity
{
QuestionId
= result.QuestionId,
Answer =
answer,
Delta =
result.Delta,
};
Then in querying ... this will fail
using (var session = documentStore.OpenSession())
{
var votes = session.Query<AnswerVote,
Votes_ByAnswerEntity>()
.Customize(x => x.WaitForNonStaleResultsAsOfNow())
.Where(x => x.AnswerId == answerId)
.As<AnswerVoteEntity>()
.ToArray();
Assert.NotNull(votes);
Assert.True(votes.Length == 2);
Assert.NotNull(votes[0].Answer);
Assert.IsType<AnswerEntity>(votes[0].Answer);
....
}
I know I can workaround this limitation by sending another query for
the AnswerEntity ... but the natural place is to have the live-
projection give me what I want.
Final thing, Is the live-projection running on the Server-side or the
Client-side ?
Much appreciated
Ayende,
I can't understand how hard it is to put the '@id' metadata value in
the 'id' property of a 'dynamic' object.
If "database.load" can load all properties of object *Foo*, why can't
it fill the 'Id' the same way? (I can't see any mysterious way to
deserialize it ... treat the 'id' as type dynamic)
2) All the deserializer to investigate special properties like
"@metadata" and read the id from it.
Thoughts ?
> ...
>
> read more »
For example, theToString will allocate a lot of memory, especially for large documents.
if (result.Value<JObject>("@metadata") == null && result.ToString().Contains("@metadata"))
Would it be possible to rewrite that ToString to read from result either using a TextReader or some kind of stream reader that you only need to buffer small parts of the document at any 1 time instead of buffering the entire doc when ToString happens?