2014-06-22 9 views
9

Mam problem z tym, aby mój model reprezentował właściwość obiektu w postaci Id jako ciąg, ale automatycznie wygenerował i reprezentował wewnętrznie MongoDb jako natywny ObjectId.Sterownik MongoDB C# - jak przechowywać _id jako ObjectId, ale odwzorować na właściwość Id łańcucha?

class Account 
{ 
    public string Id { get; set; } 
    ... 
} 

class AccountStore 
{ 
    static AccountStore() 
    { 
     BsonClassMap.RegisterClassMap<Account>(cm => 
     { 
      cm.AutoMap(); 
      cm.SetIgnoreExtraElements(true); 

      // map Id property here 
     }); 
    } 

    public void Save(Account account) 
    { 
     _accounts.Save(account); 
    } 
} 

Dla linii // map Id property here w powyższym kodzie, próbowałem wiele różnych sposobów konfiguracji mapowania identyfikatora i żaden z nich nie pracował. Sposoby próbowałem i związane z nim wyjątki, które są rzucane, gdy nazywam Save metoda, są:

// Exception: No IdGenerator found. 
cm.IdMemberMap 
    .SetRepresentation(BsonType.ObjectId); 

// Exception: No IdGenerator found. 
cm.IdMemberMap 
    .SetRepresentation(BsonType.String); 

// Exception: Unable to cast object of type 'MongoDB.Bson.ObjectId' to type 'System.String'. 
cm.IdMemberMap 
    .SetRepresentation(BsonType.ObjectId) 
    .SetIdGenerator(ObjectIdGenerator.Instance); 

// Exception: Unable to cast object of type 'MongoDB.Bson.ObjectId' to type 'System.String'. 
cm.IdMemberMap 
    .SetRepresentation(BsonType.String) 
    .SetIdGenerator(ObjectIdGenerator.Instance); 

// Exception: Unable to cast object of type 'MongoDB.Bson.ObjectId' to type 'System.String'. 
cm.IdMemberMap 
    .SetIdGenerator(ObjectIdGenerator.Instance); 

Co robię źle? Myślałem, że to był standardowy przypadek użycia do obsługi identyfikatora?

+0

Możliwy duplikat [Jak stosować atrybut BsonRepresentation umownie przy użyciu MongoDB] (https://stackoverflow.com/questions/45043266/how-to- apply-bsonrepresent ation-attribute-by-convention-when-using-mongodb) – dnickless

Odpowiedz

9

To się zmieniło, używam najnowszego sterownika 1.x (pakiet Nuget <package id="mongocsharpdriver" version="2.0.0" targetFramework="net45" />) i zamiast używać SetRepresentation ustawiasz serializator.

public class RegistrationAttempt 
{ 
    public string AttemptId { get; set; } 
} 

BsonClassMap.RegisterClassMap<RegistrationAttempt>(cm => 
{ 
    cm.AutoMap(); 
    cm.MapIdProperty(c => c.AttemptId) 
     .SetIdGenerator(StringObjectIdGenerator.Instance) 
     .SetSerializer(new StringSerializer(BsonType.ObjectId)); 
}); 
+0

@ Usunąłem edycję, która zmieniła numer wersji sterownika. Chociaż pakiet mówi 2.0.0 używam starszego sterownika, ponieważ sterownik 2.0 nie ma jeszcze wsparcia dla IQueryable. Jednak pakiet 'mongocsharpdriver' driver pobiera najnowsze pakiety sterowników, więc mógłbym się pomylić i użyć połączenia obu. Nie sądzę jednak, ponieważ otrzymałem ostrzeżenie, że część mojego kodu używa przestarzałego API – BenCr

+0

Dzięki, ten wątek obejmuje teraz oba przypadki! –

+0

Boże, do cholery! Używam ObjectIdGenerator zamiast StringObjectIdGenerator. Dziękuję Ci! Wystarczy dodać, działa to w wersji 2.4 sterownika – Phil

5

znalazł odpowiedź:

cm.IdMemberMap 
    .SetRepresentation(BsonType.ObjectId) 
    .SetIdGenerator(StringObjectIdGenerator.Instance); 

To pozwala mi zapisać jako native objectID i nadal mają Id reprezentowane w C# jako ciąg znaków. Jako mały Gotcha, identyfikator musi być analizowany przed zapytaliśmy na:

public Account GetAccountById(string id) 
{ 
    return _accounts.FindOneById(ObjectId.Parse(id)); 
} 

Edit maja 2015
Podobno kierowca się nie zmieniło od czasu, kiedy pisał tę odpowiedź. Druga powyższa odpowiedź jest poprawna w przypadku nowszych wersji, ale ta odpowiedź może być nadal przywoływana, jeśli używa się starszej wersji sterownika.

+0

Czy to jest sterownik 2.0? Nie mam funkcji SetRepresentation. – BenCr

+0

Nie jestem pewien, ale zadziałało rok temu ... –

+0

Teraz to się nie zmieniło, dostarczę aktualną odpowiedź dla osób, które dziś patrzą. – BenCr

0

W przypadku chcesz tego samego rodzaju odwzorowania w poprzek całego szeregu podmiotów bez konieczności powtórzyć się w kółko możesz używać konwencji:

public class 
StringObjectIdIdGeneratorConventionThatWorks : 
ConventionBase, IPostProcessingConvention 
{ 
    /// <summary> 
    /// Applies a post processing modification to the class map. 
    /// </summary> 
    /// <param name="classMap">The class map.</param> 
    public void PostProcess(BsonClassMap classMap) 
    { 
     var idMemberMap = classMap.IdMemberMap; 
     if (idMemberMap == null || idMemberMap.IdGenerator != null) 
      return; 
     if (idMemberMap.MemberType == typeof(string)) 
     { 
      idMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance).SetSerializer(new StringSerializer(BsonType.ObjectId)); 
     } 
    } 
} 

.. .i następnie używać go w miejsce wszystkich niestandardowych odwzorowań:

ConventionPack cp = new ConventionPack(); 
cp.Add(new StringObjectIdIdGeneratorConventionThatWorks()); 

ConventionRegistry.Register("TreatAllStringIdsProperly", cp, _ => true); 
Powiązane problemy