2012-04-19 7 views
17

Sto lavorando su un progetto che utilizza .NET Razor e mongodb. Mi piacerebbe fare qualcosa di simile:Esiste il supporto per il driver C# di mongodb System.Dynamic.DynamicObject in .NET 4?

@{ 
    var feeds = DP.Database.GetCollection("feeds").FindAll(); 
} 
<ul> 
    @foreach (dynamic feed in feeds) 
    { 
     <li>@feed.message - @feed.from.name</li> 
    } 
</ul> 

Tuttavia, la collezione di ritorno della corrente mongodb C# conducente FindAll() di BsonDocument che non supporta oggetto dinamico. Qualcuno conosce un driver mongodb C# supportato da .NET 4?

Grazie mille

risposta

14

Attualmente, non v'è alcun supporto per dinamica nel driver MongoDB. Questo perché è basato su .NET 3.5. Tuttavia, poiché un assembly .NET 4.0 può fare riferimento a un assembly .NET 3.5, è possibile scrivere un IBsonSerializationProvider e un IBsonSerializer in .NET 4.0 per supportare le dinamiche.

Noi, 10gen, stiamo cercando di farlo in futuro. Ho spinato qualche supporto allo https://github.com/craiggwilson/mongo-csharp-driver/tree/dynamic se vuoi dare un'occhiata. Ci sono sicuramente bug, ma mostra che è possibile.

+0

Grazie Craig, ho trovato un modo per farlo funzionare. controlla qui https://groups.google.com/forum/?fromgroups#!topic/mongodb-user/AEIfBP9IWQw – hoang

+1

Sì, l'ho visto. Farò eco qui per gli utenti SO. Funziona bene, ma richiede una modifica di basso livello al nucleo.Il modo in cui ho presentato sopra è un carico laterale e realizza la stessa cosa senza modificare il nucleo. Ovviamente, ci sono alcune differenze, ma la maggior parte del modo lì. Dopotutto è solo un picco, quindi ... –

+1

Dai un'occhiata a [MongoDB.Dynamic] (http://www.assembla.com/spaces/mongodb-dynamic/wiki). Utilizza il driver ufficiale MongoDB e ha un approccio di utilizzo delle interfacce con la dinamica di C# 4.0. –

16

Ho creato un'estensione diretta del driver MongoDB che serializza nuovamente il documento BSON utilizzando Json.NET e lo deserializza come dinamico. Includendo la seguente classe, si può semplicemente convertire le vostre domande a MongoDB dinamica come questa classe

dynamic obj = collection.FindOneByIdAs<BsonDocument>(someObjectId).ToDynamic(); 

Estensione:

public static class MongoDynamic 
{ 
    private static System.Text.RegularExpressions.Regex objectIdReplace = new System.Text.RegularExpressions.Regex(@"ObjectId\((.[a-f0-9]{24}.)\)", System.Text.RegularExpressions.RegexOptions.Compiled); 
    /// <summary> 
    /// deserializes this bson doc to a .net dynamic object 
    /// </summary> 
    /// <param name="bson">bson doc to convert to dynamic</param> 
    public static dynamic ToDynamic(this BsonDocument bson) 
    { 
     var json = objectIdReplace.Replace(bson.ToJson(), (s) => s.Groups[1].Value); 
     return Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json); 
    } 
} 

sicuro riferire Newtonsoft.Json.dll (http://james.newtonking.com/projects/json-net.aspx)

+1

L'uso di 'bson.ToJson (new JsonWriterSettings {OutputMode = JsonOutputMode.Strict})' rimuove la necessità per tutto il processamento Regex di rimuovere i metodi Json specifici di Mongo. –

4

Solo per costruire la risposta di Massimiliano. Ciò restituirà un elenco di dinamiche da qualsiasi query.

/// <summary> 
    /// deserializes this BsonDocument cursor result to a list of .net dynamic objects 
    /// </summary> 
    /// <param name="cursor">cursor result to convert to dynamic</param> 
    /// <returns></returns> 
    public static List<dynamic> ToDynamicList(this MongoCursor<BsonDocument> cursor) 
    { 
     var dynamicList = new List<dynamic>(); 
     var list = cursor.ToList(); 
     for (int i = 0, l = list.Count; i < l; i++) 
      dynamicList.Add(list[i].ToDynamic()); 

     return dynamicList; 
    } 
+2

Questo sembra ridondante. Potresti semplicemente fare 'cursor.Select (doc => doc.ToDynamic())'. Aggiungi '.ToList()' se necessario. In generale, i metodi di scrittura per i quali il framework fornisce già una buona soluzione dovrebbero essere evitati. – Tomas

5

Ho una soluzione pulita utilizzando IBsonSerializer e Newtonsoft.Json personalizzati.

Imposta il tuo serializzatore personalizzato sul BsonClassMap

map.MapProperty(member => member.Data) 
    .SetElementName("Data") 
    .SetSerializer(new DynamicSerializer()); 

o sulla proprietà

[BsonSerializer(typeof(DynamicSerializer))] 
public dynamic Data { get; set; } 

E proprio includono la seguente classe

public class DynamicSerializer : IBsonSerializer 
{ 
    #region Implementation of IBsonSerializer 

    public object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options) 
    { 
    return Deserialize(bsonReader, nominalType, null, options); 
    } 

    public object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, 
    IBsonSerializationOptions options) 
    { 
    if (bsonReader.GetCurrentBsonType() != BsonType.Document) throw new Exception("Not document"); 
    var bsonDocument = BsonSerializer.Deserialize(bsonReader, typeof(BsonDocument), options) as BsonDocument; 
    return JsonConvert.DeserializeObject<dynamic>(bsonDocument.ToJson()); 
    } 

    public IBsonSerializationOptions GetDefaultSerializationOptions() 
    { 
    return new DocumentSerializationOptions(); 
    } 

    public void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options) 
    { 
    var json = (value == null) ? "{}": JsonConvert.SerializeObject(value); 
    BsonDocument document = BsonDocument.Parse(json); 
    BsonSerializer.Serialize(bsonWriter, typeof(BsonDocument), document,options); 
    } 

    #endregion 
} 

InfoSlips - GlobalKinetic

+1

puoi dare un esempio su come deserilizzare un singolo bsondocument in dinamico? –

0

Anche se questo è un vecchio argomento è ancora altrettanto rilevante oggi come quando è stato fatto un post, e devo ancora vedere tutte le soluzioni là fuori che fornisce una soluzione semplice per il supporto bidirezionale, ho modificato il codice @Maximilian Scherer in modo che ti consente di convertire in oggetti dinamici che ti consentono di salvare di nuovo il tuo documento.

public static class MongoDynamic 
{ 
    /// <summary> 
    /// deserializes this bson doc to a .net dynamic object 
    /// </summary> 
    /// <param name="bson">bson doc to convert to dynamic</param> 
    public static dynamic ToDynamic(this BsonDocument bson) 
    { 
     var json = bson.ToJson(new MongoDB.Bson.IO.JsonWriterSettings { OutputMode = JsonOutputMode.Strict }); 
     dynamic e = Newtonsoft.Json.JsonConvert.DeserializeObject<ExpandoObject>(json); 
     BsonValue id; 
     if (bson.TryGetValue("_id", out id)) 
     { 
      // Lets set _id again so that its possible to save document. 
      e._id = new ObjectId(id.ToString()); 
     } 
     return e; 
    } 
} 

Esempio di utilizzo:

// Get BsonDocument from db here 
BsonDocument doc = ... 

// Convert to dynamic. 
var d = doc.ToDynamic(); 

// Lets add a none existant property. 
d.Name = "test"; 

// Assuming you already have your collection set up 
collection.Save(new BsonDocument(d));