RavenDB throws casting exception after models namespace change

﹥>﹥吖頭↗ 提交于 2019-12-10 02:14:17

问题


In the database, I have already stored hundreds of documents. Now the system architecture has changed and (among others) models was migrated into different namespace (in different assembly).

Below, metadata of sample document is shown:

and code I'm using to fetch such document:

var configuration = documentSession.Load<One.Social.Core.Entities.Setting>("Setting");

which throws casting exception:

[InvalidCastException: Unable to cast object of type 'One.QA.Core.Entities.Setting' to type 'One.Social.Core.Entities.Setting'.]

UPDATE:

Similiar error but from NewtonsoftJson rises, while I have collection of specified type inside the dosument, which now changed.

In database I have Question document, which contains a list of Answers:

In the code, the type looks like that:

namespace One.Social.Ask.Web.Models
{
    public class Question
    {        
        public string Content { get; set; }
        public IList<One.Social.Ask.Web.Models.Answer> Answers { get; set; }        
    }
}

Answers namespace changed. In addition, now it's derived from IList<>, no ICollection<>. I don't need the $type meta now, it should be:

.

While it is a list now, an error rises because of the old $type information:

Newtonsoft.Json.JsonSerializationException: Error resolving type specified in JSON 'System.Collections.ObjectModel.Collection`1[[One.QA.Core.Entities.Answer, One.QA.Core]], mscorlib'. ---> Newtonsoft.Json.JsonSerializationException: Could not find type 'System.Collections.ObjectModel.Collection`1[[One.QA.Core.Entities.Answer, One.QA.Core]]' in assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

What is the best way to migrate all documents to reflect current types names ? Is there any built in mechanism ?

Btw: I'm using RavenDB - Build #960


回答1:


Jarek, The reason for the issue is that you HAVE both types. If you remove the QA type, it will just work. Or, you can do as Wyatt suggested and force this.




回答2:


I had the same problem and 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);



回答3:


You'll need to patch the ravendb documents directly without attempting to deserialize them. I haven't ever had to do this myself, but I think the magic is done using the methods found in IDocumentSession.Advanced.DatabaseCommands, particularly the Patch method.

I don't really have anything to test against, but I think the code should look like:

//s is your document session
var toUpdate = s.Advanced.DatabaseCommands.StartsWith("Setting", 0, 128);
foreach (var d in toUpdate)
{
    var p = new PatchRequest();
    p.AllPositions = true;
    p.Type = PatchCommandType.Modify;
    d.Metadata["Raven-Clr-Type"] = "MyNewType";
    p.Value = d.ToJson();
    s.Advanced.DatabaseCommands.Patch(d.Key, new []{p});
}
// push forward and repeat for all items in collection

There is also a way to do this without looping through the collection but I'm not sure how to effect that properly.




回答4:


I faced the exact same issue of casting exception after a renaming. As advised in the previous answers, I ended up patching all my documents based on this snippet.

We need to update two fields: Raven-Entity-Name and Raven-Clr-Type.

Example

Renaming MyType to MyNewType, updating the namespace from My.Namespace.MyType to My.New.Namespace.MyNewType.

Raven-Entity-Name needs to be changed from MyTypes to MyNewTypes. Why plural? "Convention over configuration" approach, as explained here.

Raven-Clr-Type needs to be updated from My.Namespace.MyType to My.New.Namespace.MyNewType.

Code

public static void PatchMetadata()
        {
            var operation = session.Advanced.DocumentStore.DatabaseCommands
            .UpdateByIndex(
                // You can check your index name in the Studio Under INDEXES.
                    "Raven/DocumentsByEntityName",
                //  query that will be performed
                    new IndexQuery
                    {
                        // A collection in RavenDB is a set of documents with the same tag. 
                        // The tag is defined in Raven-Entity-Name.
                        Query = "Tag:MyTypes"
                    }, new[]
                                {
                                    new PatchRequest
                                        {
                                            Type = PatchCommandType.Modify,
                                            Name = "@metadata",
                                            Nested = new[]
                                                {
                                                    new PatchRequest
                                                        {
                                                            Type = PatchCommandType.Set,
                                                            Name = "Raven-Entity-Name",
                                                            Value = new RavenJValue("MyNewTypes")
                                                        }
                                                        ,
                                                    new PatchRequest
                                                        {
                                                            Type = PatchCommandType.Set,
                                                            Name = "Raven-Clr-Type",
                                                            Value = new RavenJValue("My.New.Namespace.MyNewType, RavenDbPatching")
                                                        }
                                                }
                                        }
                                },
                    new BulkOperationOptions() { AllowStale = true }
            );
        }


来源:https://stackoverflow.com/questions/11224248/ravendb-throws-casting-exception-after-models-namespace-change

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!