问题
这是交易,如果您有一个dynamic
属性,那么 RavenDB 将始终将其反序列化为RavenJObject
. 例如:
public class User {
public dynamic Data = new ExpandoObject();
}
...
var user = new User();
user.Data.SomethingNew1 = "foo";
当您创建用户时,这看起来无害并且工作正常。但是当你加载用户时,RavenDB 不知道你想要什么类型,dynamic
所以它使用RavenJObject
. 您无法动态创建属性(扩展样式),RavenJObject
因此失败:
var user = session.Find<User>(...);
user.Data.SomethingNew2 = "foo"; //compiles, but throws
我的解决方案
ExpandoObject
在序列化的属性中使用并显式定义其类型。这让 RavenDB(或者我猜是 JSON)知道你期待什么类型并且它不必猜测RavenJObject
。然后,为了保持你的语法魔力,用动态访问器包装属性。
public class User {
public ExpandoObject _Data = new ExpandoObject();
public dynamic Data {
get { return _Data; }
}
}
有一些方法可以使 expando 对象私有并为 . 创建一个 setter Data
,但你明白了。
更多问题
更新:不幸的是,这个解决方案暴露了更多问题。假设您在动态数据中存储了一个字符串列表:
user.Data.Keys = new List<String>{"a","b","c"};
在您序列化/反序列化之后,JSON/Raven 再次不知道您期望什么类型。因此,如果您尝试这个(见下文),那么它会编译,但您会得到一个运行时异常,无法将类型 'Raven.Abstractions.Linq.DynamicList' 隐式转换为 'System.Collections.Generic.List':
List<string> keys = user.Data.Keys;