How to use a reference type as a key in a document in RavenDB

蓝咒 提交于 2019-12-11 03:14:43

问题


I have a class that I want to use for a document key in RavenDB:

public class DocumentKey
{
    public string Namespace { get; set; }
    public string Id { get; set; }
}

I've also implemented the ITypeConverter (not the .NET one, the RavenDB-specific one) interface to convert from the reference type to a string (because in the database, the keys are all really just strings).

Finally, I've added the implementation of ITypeConverter to the IDocumentStore implementation through the List<ITypeConverter> exposed through the Conventions.IdentityProviders property.

However, the signature on the LoadAsync<T> overloads on the IAsyncDocumentSession implementation look like this (removed the signatures which take multiple ids for brevity. Also, the same as Load on the IDocumentSession interface):

LoadAsync<T>(string id);
LoadAsync<T>(ValueType id);

I really don't want to use value types for my keys for the following reasons:

  • I have an abstraction which doesn't have a constraint on the type of the key. Creating separate structures to mirror this just to have value types are very inconvenient.
  • I don't have complete control over the type by being restricted to a value type. The value type has a default constructor which defaults the values in a way that I don't want to have to deal with everywhere else in my code.

How can I use a reference type as a document key in RavenDB?


回答1:


Because all document identifiers are stored ultimately stored as strings in RavenDB, the key is using the overload that takes a string:

LoadAsync<T>(string id);

From the IAsyncDocumentSession interface, you can use the Conventions (exposed by Advanced.DocumentStore.Conventions), specifically the FindFullDocumentKeyFromNonStringIdentifier delegate, which has the following signature:

string FindFullDocumentKeyFromNonStringIdentifier(
    object id, Type type, bool allowNull);

Here is what the parameters do:

  • id - This is the object that is being used as the identifier for the document. In the above example, it would be the DocumentKey instance. Since this is typed as an object (and not a ValueType), a reference type will be accepted here.
  • type - The Type instance that represents the type of the item that the id belongs to. When calling LoadAsync<T>, this is typeof(T).
  • allowNull - This is passed as the allowNull parameter in the implementation of ITypeConverter.ConvertFrom that is added to the IdentityProviders exposed through Conventions.

This can all be wrapped up in an extension method on IAsyncDocumentSession (or modified for IDocumentSession if you want) that is strongly typed, like so:

static Task<T> LoadAsync<T, TId>(this IAsyncDocumentSession session, TId id)
{
    // Validate parameters.
    if (session == null) throw new ArgumentNullException("session");
    // Check if the id is null.
    if ((object) id == null) throw new ArgumentNullException("id");

    // Get the string id.
    string stringId = session.Advanced.DocumentStore.Conventions.
        FindFullDocumentKeyFromNonStringIdentifier(id, typeof(T), true);

    // Load using the string id.
    return session.LoadAsync<T>(stringId);
}

Note that the if ((object) id == null) comparison can have a performance impact in this scenario.



来源:https://stackoverflow.com/questions/14005053/how-to-use-a-reference-type-as-a-key-in-a-document-in-ravendb

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