问题
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