Reputation: 16012
I get the following error when storing my object(s) in RavenDb
I am only assigning one key to the stored object, I am using the overloaded store method to store the entity.
Store is only called once so why would an exception like this be thrown. There is something about object identity I don't understand.
The Id
property has another purpose besides ravendb persistence.
Entity UserQuery+MyItem had document key 'mykeypath/44' but now has document key property 'MyItems/44'. You cannot change the document key property of a entity loaded into the session
.
void Main()
{
var host = "http://myhost:8020";
var _documentStore = new DocumentStore { Url = host, DefaultDatabase = "sdb" };
_documentStore.Initialize();
using (var session = _documentStore.OpenSession())
{
var path = "mykeypath/44";
session.Store(new MyItem { Id = 303, Test = "TEST" }, path);
session.SaveChanges();
}
}
public class MyItem : AuditableEntity {
public string Test { get; set; }
}
[Serializable]
public abstract class AuditableEntity : IAuditable
{
[DataMember]
[Display(Name = "Id", Description = "Id")]
public long Id { get; set; }
[DataMember]
[Display(Name = "Modified By", Description = "Modified By")]
public string ModifiedBy { get; set; }
[DataMember]
[Display(Name = "Modified Date", Description = "Modified Date")]
public DateTime ModifiedDate { get; set; }
}
Upvotes: 2
Views: 1177
Reputation: 40526
If your class has a property called Id
, RavenDB will use that as document id by default.
In your case, having an instance of MyItem
with Id
set to 303
, means that the document will be saved in the database with an Id of MyItems/303
.
You can test that easily by modifying the
session.Store(new MyItem { Id = 303, Test = "TEST" }, path);
line with
session.Store(new MyItem { Id = 303, Test = "TEST" });
This will work and the result will be:
So, the issue is that you are instructing Raven to assign two IDs to your object:
MyItems/303
, due to the value of the Id
propertymykeypath/44
, due to the fact that you're explicitly setting this Id by using the Store
overload.The solution I would apply in this case is to rename the Id
property. If that's not possible (ex: the class is already used for other purposes, like a WCF contract), consider creating a new class used solely for RavenDB persistence and map between the two (tools like AutoMapper make this easy).
I found a way to bend the Id
field convention by looking at this thread.
In your case, you should do the following prior to opening the session:
_documentStore.Conventions.FindIdentityProperty =
prop =>
{
if (prop.DeclaringType == typeof (AuditableEntity))
return prop.Name == "CustomId";
return prop.Name == "Id";
};
What this says is that the property Id
defined by the type AuditableEntity
should not be used as a document identifier. In all other cases, do the default.
I tested it and it works fine, showing two Id fields in the RavenDb studio :) :
Upvotes: 3