如何在RavenDB中正确建模松散类型的属性

时间:2012-01-31 23:36:59

标签: persistence ravendb json.net

我是RavenDB的新手,正在寻找有关存储松散类型数据的正确方法的指导。我有一个键/值对列表的类型。在设计时不知道value属性的类型。

public class DescriptiveValue
{
    public string Key { get; set; }

    public object Value { get; set; }
}

当我查询使用DateTime或Guid Value保存的DescriptiveValue时,反序列化的数据类型是字符串。数值似乎保留其数据类型。

是否有一个优雅的解决方案来保留数据类型或者我应该只将所有值存储为字符串?如果我去字符串路由,当我以后想要对这些数据进行排序和过滤时(这可能是通过索引?)这会限制我吗?

我希望这是一个容易解决的常见问题,而我只是错误地思考问题。非常感谢您的帮助!

更新: 此单元测试的输出为:Assert.AreEqual失败。预计:< 2/2/2012 10:00:01 AM(System.DateTime)>。实际:< 2012-02-02T10:00:01.9047999(System.String)>。

[TestMethod]
public void Store_WithDateTime_IsPersistedCorrectly()
{
    AssertValueIsPersisted<DateTime>(DateTime.Now);
}

private void AssertValueIsPersisted<T>(T value)
{
    ObjectValuedAttribute expected = new ObjectValuedAttribute() { Value = value };
    using (var session = this.NewSession())
    {
        session.Store(expected);
        session.SaveChanges();
    }

    TestDataFactory.ResetRavenDbConnection();

    using (var session = this.NewSession())
    {
        ObjectValuedAttribute actual = session.Query<ObjectValuedAttribute>().Single();

        Assert.AreEqual(expected.Value, actual.Value);
    }
}

我希望实际是一个DateTime值。

2 个答案:

答案 0 :(得分:2)

绝对 - 这是无模式文档数据库的优势之一。见这里:http://ravendb.net/docs/client-api/advanced/dynamic-fields

答案 1 :(得分:1)

问题是RavenDB服务器没有Value类型的概念。将对象发送到服务器时,Value将作为字符串保留,当您稍后查询该文档时,反序列化程序不知道原始类型,因此Value被反序列化为字符串。 / p>

您可以通过将原始类型信息添加到ObjectValuedAttribute

来解决此问题
public class ObjectValuedAttribute {
    private object _value;
    public string Key { get; set; }
    public object Value {
        get {
            // convert the value back to the original type
            if (ValueType != null && _value.GetType() != ValueType) {
                _value = TypeDescriptor
                    .GetConverter(ValueType).ConvertFrom(_value);
            }

            return _value;
        }
        set { 
            _value = value;
            ValueType = value.GetType();
        }
    }
    public Type ValueType { get; private set; }
}

Value的设置器中,我们还存储它的类型。稍后,当取回值时,我们将其转换回原始类型。

以下测试通过:

public class CodeChef : LocalClientTest {
    public class ObjectValuedAttribute {
        private object _value;
        public string Key { get; set; }
        public object Value {
            get {
                // convert value back to the original type
                if (ValueType != null && _value.GetType() != ValueType) {
                    _value = TypeDescriptor
                        .GetConverter(ValueType).ConvertFrom(_value);
                }

                return _value;
            }
            set { 
                _value = value;
                ValueType = value.GetType();
            }
        }
        public Type ValueType { get; private set; }
    }

    [Fact]
    public void Store_WithDateTime_IsPersistedCorrectly() {
        AssertValueIsPersisted(DateTime.Now);
    }

    private void AssertValueIsPersisted<T>(T value) {
        using (var store = NewDocumentStore()) {
            var expected = new ObjectValuedAttribute { Value = value };
            using (var session = store.OpenSession()) {
                session.Store(expected);
                session.SaveChanges();
            }

            using (var session = store.OpenSession()) {
                var actual = session
                    .Query<ObjectValuedAttribute>()
                    .Customize(x => x.WaitForNonStaleResults())
                    .Single();

                Assert.Equal(expected.Value, actual.Value);
            }
        }
    }
}