AsProjection not returning values that are nested in map statement

354 views
Skip to first unread message

Chris Marisic

unread,
Feb 22, 2012, 2:55:07 PM2/22/12
to rav...@googlegroups.com
I have an index as such:

public class ContactIndex : AbstractIndexCreationTask<Contact>
{
    public ContactIndex()
    {
        Map = contacts => from contact in contacts
                        select new
                                   {
                                       contact.Name,
                                       PrimaryEmail_EmailAddress = contact.PrimaryEmail.EmailAddress,
                                       PrimaryPhone_PhoneNumber = contact.PrimaryPhone.PhoneNumber,
                                   };       
    }   

    public class IndexResult
    {
        public string Id { get; set; }
        public string Name { get; set; }           
        public string EmailAddress { get; set; }
        public string PrimaryPhone_PhoneNumber { get; set; }
    }
}

Note, on my IndexResult I have conflicting usages of Email & Phone for illustration.

When querying:

_session.Query<Contact, ContactIndex>().AsProjection<ContactIndex.IndexResult>().ToList()

My result set has Id, Name set fine, however neither EmailAddress, PrimaryEmail_EmailAddress, PhoneNumber, PrimaryPhone_PhoneNumber have any values.

When opening the index in the management studio I correctly see in the terms view the correct terms inside of PrimaryEmail_EmailAddress and PrimaryPhone_PhoneNumber

Matt Warren

unread,
Feb 22, 2012, 4:52:35 PM2/22/12
to rav...@googlegroups.com
I wonder if the "_" (underscore) characters in the property names are confusing RavenDB, is has some conventions that use this.

What happens if you remove all the "_" characters from your property names inside the Select part of your Map statement?

Chris Marisic

unread,
Feb 22, 2012, 5:08:38 PM2/22/12
to rav...@googlegroups.com
If i would remove those underscores I would no longer be able to query against the full documents like:

_session.Query<Contact, ContactIndex>().Where(x=> x.PrimaryEmail.EmailAddress == "em...@site.com").ToList()

Chris Marisic

unread,
Feb 22, 2012, 5:09:14 PM2/22/12
to rav...@googlegroups.com
Although I suppose I could keep duplicate fields for the different names, but that seems silly.

Itamar Syn-Hershko

unread,
Feb 22, 2012, 5:24:30 PM2/22/12
to rav...@googlegroups.com
You need to have those fields marked as stored

Chris Marisic

unread,
Feb 23, 2012, 8:53:30 AM2/23/12
to rav...@googlegroups.com
Itamar could you please explain when things need stored vs when they do not.

When I view the terms in the management studio, is that actually doing like a fake query to show me what terms would be there? as opposed to showing me whats directly in the index because it's not stored?

Oren Eini (Ayende Rahien)

unread,
Feb 23, 2012, 8:58:04 AM2/23/12
to rav...@googlegroups.com
Chris,
Terms is taken without relation to a document.
When you want to do a projection, and it is not on the root of the object, you need to store it.
When it is on the root of the object, we can pull it from the doc, but not when it is nested.

Chris Marisic

unread,
Feb 23, 2012, 10:02:48 AM2/23/12
to rav...@googlegroups.com


On Thursday, February 23, 2012 8:58:04 AM UTC-5, Ayende Rahien wrote:
Chris,
Terms is taken without relation to a document.
When you want to do a projection, and it is not on the root of the object, you need to store it.
When it is on the root of the object, we can pull it from the doc, but not when it is nested.


I think this information would be very relevant for the site documentation. I did a search on google for site:old.ravendb.net asprojection and site:ravendb.net asprojection and it doesn't seem to even have AsProjection, especially about how it's reading from the doc's top level fields otherwise it needs stored fields.

Chris Marisic

unread,
Feb 23, 2012, 10:26:20 AM2/23/12
to rav...@googlegroups.com
Updated index to be:


    public ContactIndex()
    {
        Map = contacts => from contact in contacts
                        select new
                                   {
                                       contact.Name,
                                       PrimaryEmail_EmailAddress = contact.PrimaryEmail.EmailAddress,
                                       PrimaryPhone_PhoneNumber = contact.PrimaryPhone.PhoneNumber,
                                   };       

            Store(x => x.PrimaryEmail.EmailAddress, FieldStorage.Yes);
            Store(x => x.PrimaryPhone.PhoneNumber, FieldStorage.Yes);
    }   

_session.Query<Contact, ContactIndex>().AsProjection<ContactIndex.IndexResult>().ToList()

Still none of EmailAddress, PrimaryEmail_EmailAddress, PhoneNumber, PrimaryPhone_PhoneNumber have any values.


On Thursday, February 23, 2012 8:58:04 AM UTC-5, Ayende Rahien wrote:

Chris Marisic

unread,
Feb 23, 2012, 10:35:15 AM2/23/12
to rav...@googlegroups.com
Further strangeness with AsProjection, in my domain Contact is a Person ( class  Contract : Person ). All of those properties are properties of the person object, except for Id which are on Contact being an aggregate root.

If I change

    public class IndexResult
    {
        public string Id { get; set; }
        public string Name { get; set; }           
        public string EmailAddress { get; set; }
        public string PrimaryPhone_PhoneNumber { get; set; }
    }

To be

    public class IndexResult : Person

    {
        public string Id { get; set; }
    }


When I query

_session.Query<Contact, ContactIndex>().AsProjection<ContactIndex.IndexResult>().ToList()

The IndexResult objects are fully hydrated with all of the Person data which contains many other fields and sub objects. The only store settings I have are on the fields for  x.PrimaryEmail.EmailAddress, x.PrimaryPhone.PhoneNumber,

Oren Eini (Ayende Rahien)

unread,
Feb 23, 2012, 2:56:18 PM2/23/12
to rav...@googlegroups.com
The fields names are " PrimaryPhone_PhoneNumber  ", but you are using this:
            Store(x => x.PrimaryPhone.PhoneNumber, FieldStorage.Yes);

This tries to store a field named PhoneNumber.

Oren Eini (Ayende Rahien)

unread,
Feb 23, 2012, 2:56:55 PM2/23/12
to rav...@googlegroups.com
For simple props, we can load it from the document, but for nested props, we can't.

Chris Marisic

unread,
Feb 23, 2012, 3:19:03 PM2/23/12
to rav...@googlegroups.com
That's extremely nonobvious when you factor in the magic of PrimaryPhone_PhoneNumber matching Where(x=>x.PrimaryPhone.PhoneNumber == "123") and that Store only supports strongly typed registrations.

Oren Eini (Ayende Rahien)

unread,
Feb 23, 2012, 3:20:07 PM2/23/12
to rav...@googlegroups.com
I agree, can you open an issue for this?

Chris Marisic

unread,
Feb 23, 2012, 3:28:01 PM2/23/12
to rav...@googlegroups.com
Should I open the issue that   Store(x => x.PrimaryPhone.PhoneNumber, FieldStorage.Yes) should match PrimaryPhone_PhoneNumber = contact.PrimaryPhone.PhoneNumb
er,

or that I should be able to do

Store("PrimaryPhone_PhoneNumber", FieldStorage.Yes)

or should i open 2 issues to cover both of these?

Oren Eini (Ayende Rahien)

unread,
Feb 23, 2012, 3:35:42 PM2/23/12
to rav...@googlegroups.com
Both

Chris Marisic

unread,
Feb 24, 2012, 8:58:03 AM2/24/12
to rav...@googlegroups.com
Issues 80 & 81 opened

Oren Eini (Ayende Rahien)

unread,
Feb 24, 2012, 11:01:13 AM2/24/12
to rav...@googlegroups.com
Thanks, we will look them over on Sunday
Reply all
Reply to author
Forward
0 new messages