Question

I've just completed a round of refactoring of my application, which has resulted in my removing a project that was no longer required and moving its classes into a different project. A side effect of this is that my User class, which is stored in RavenDB, has a collection property of a type moved to the new assembly. As soon as I attempt to query the session for the User class I get a Json deserialisation error. The issue is touched upon here but the answers don't address my issue. Here's the offending property:

{
  "OAuthAccounts": {
    "$type": "System.Collections.ObjectModel.Collection`1[
      [Friendorsement.Contracts.Membership.IOAuthAccount, 
      Friendorsement.Contracts]], mscorlib",
    "$values": []
  },
}

OAuthAccounts is a collection property of User that used to map here:

System.Collections.ObjectModel.Collection`1[[Friendorsement.Contracts.Membership.IOAuthAccount, Friendorsement.Contracts]]

It now maps here:

System.Collections.ObjectModel.Collection`1[[Friendorsement.Domain.Membership.IOAuthAccount, Friendorsement.Domain]]

Friendorsement.Contracts no longer exists. All of its types are now in Friendorsement.Domain

I've tried using store.DatabaseCommands.StartsWith("User", "", 0, 128) but that didn't return anything.

I've tried looking at UpdateByIndex but not got very far with it:

store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
    new IndexQuery {Query = "Tag:Users"},
        new[]
        {
            new PatchRequest { // unsure what to set here }
        });

I'm using Raven 2.0

Was it helpful?

Solution

Below is a simple sample application that shows you the patching Metadata. While your example is a little different this should be a good starting point

namespace SO19941925
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            IDocumentStore store = new DocumentStore
                                   {
                                       Url = "http://localhost:8080",
                                       DefaultDatabase = "SO19941925"
                                   }.Initialize();

            using (IDocumentSession session = store.OpenSession())
            {
                for (int i = 0; i < 10; i++)
                {
                    session.Store(new User {Name = "User" + i});
                }
                session.SaveChanges();
            }

            using (IDocumentSession session = store.OpenSession())
            {
                List<User> users = session.Query<User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).ToList();
                Console.WriteLine("{0} SO19941925.Users", users.Count);
            }

            Operation s = store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
                new IndexQuery {Query = "Tag:Users"},
                new ScriptedPatchRequest
                {
                    Script = @"this['@metadata']['Raven-Clr-Type'] = 'SO19941925.Models.User, SO19941925';"
                }, true
                );
            s.WaitForCompletion();
            using (IDocumentSession session = store.OpenSession())
            {
                List<Models.User> users =
                    session.Query<Models.User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).ToList();
                Console.WriteLine("{0} SO19941925.Models.Users", users.Count);
            }
            Console.ReadLine();
        }
    }

    internal class User
    {
        public string Name { get; set; }
    }
}

namespace SO19941925.Models
{
    internal class User
    {
        public string Name { get; set; }
    }
}

UPDATE: Based on the initial answer above, here is the code that actually solves the OP question:

store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
    new IndexQuery {Query = "Tag:Users"},
    new ScriptedPatchRequest
    {
        Script = @"this['OAuthAccounts']['$type'] = 
            'System.Collections.ObjectModel.Collection`1[
            [Friendorsement.Domain.Membership.IFlexOAuthAccount, 
            Friendorsement.Domain]], mscorlib';",
        }, true
        );

OTHER TIPS

Here are two possible solutions:

Option 1: Depending on what state your project is in, for example if you are still in development, you could easily just delete that collection out of RavenDB from the Raven Studio and recreate all those User documents. All the new User documents should then have the correct class name and assembly and should then deserialize correctly. Obviously, if you are already in production, this probably won't be a good option.

Option 2: Depending on how many User documents you have, you should be able to manually edit each one to specify the correct C# class name and assembly, so that they will be deserialized correctly. Again, if you have too many objects to manually modify, this may not be a good option; however, if there are just a few, it shouldn't be too bad to open each one up go to the metadata tab and paste the correct value for "Raven-Entity-Name" and "Raven-Clr-Type".

I ended up doing this:

Advanced.DatabaseCommands.UpdateByIndex(
    "Raven/DocumentsByEntityName",
        new IndexQuery {Query = "Tag:Album"},
        new []{ new PatchRequest() { 
            Type = PatchCommandType.Modify, 
            Name = "@metadata", 
            Nested= new []{ 
                new PatchRequest{
                    Name= "Raven-Clr-Type",
                    Type = PatchCommandType.Set,
                    Value = "Core.Model.Album, Core" }}}},
        false);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top