Devel.cz Lupa Měšec Podnikatel Root Zdroják.cz DigiZone Slunečnice Vitalia TopDrive KupDnes Navrcholu NovýTarif Dobrý web Weblogy Woko Jagg Computer.cz SK: MojeLinky

Hlavní navigace

Praktické použitie MongoDB v .NET

NoSQL databázy naberajú v súčasnosti na populárnosti, dlhšie som sa chystal nejakú z nich vyskúšať. Pri práci na aktuálnom projekte som mal na to konečne možnosť, zvolil som riešenie Microsoft .NET.

Tweetni to Twitter Jaggni to! Jagg Del.icio.us Delicious

Zadanie problému

Aplikácia, na ktorej som pracoval, komunikovala s MS SQL databázou a LDAPom bežiacimi na vzdialených počítačoch. Jej úlohou bolo každý deň natiahnúť dáta z LDAPu, transformovať ich, porovnať ich stav s aktuálnym stavom v MS SQL a premietnuť do MS SQL všetky zmeny za posledný deň. Hlavný dôraz sa kládol na rýchlosť.

Keďže dopyty do MS SQL databázy (ktorá naviac beží na vzdialenom počítači) sú dosť pomalé, jasnou voľbou bolo čiastkové natiahnutie potrebných záznamov do pamäte a práca s nimi v pamäti. Platforma Microsoft .NET však na 32-bitovom operačnom systéme obsahuje obmedzenie maximálnej alokovanej pamäte na cca 2 GB, vzhľadom na veľké množstvo záznamov (rádovo státisíce) nebolo možné tieto záznamy v pamäti udržiavať. Bolo potrebné nájsť iné rýchle riešenie s podporou dopytovania.

Dôvod použitia NoSQL databázy

Ako dobrý nápad sa zdalo použitie nejakej NoSQL databázy. NoSQL databázy bývajú na rozdiel od klasických SQL databáz optimalizované na veľké množstvo read/write operácií. Celý nápad spočíval v tom, že na stroji, kde beží aplikácia, bude bežať lokálne aj NoSQL databáza. Aplikácia natiahne záznamy zo vzdialeného MS SQL servera a uloží ich do lokálnej NoSQL databázy. Dotazovanie bude namiesto do hash mapy v pamäti prebiehať do NoSQL databázy, kde kľúč pôvodnej hash mapy bude zodpovedať kľúču NoSQL databázy. Dané riešenie bude určite rýchlejšie ako dopytovanie do vzdialenej MS SQL databázy a nenarazí na limit pamäte.

MongoDB

Ako NoSQL databáza bola zvolená MongoDB. Výhodou je, že MongoDB nie je potrebné inštalovať, je dostupná pre rôzne platformy, skladá sa z pár binárnych súborov a vyžaduje len adresár na uloženie dát. Môže byť teda jednoducho distribuovaná spolu s vašim programom. Stačí, ak túto NoSQL databázu spustíte pred behom vášho programu a ukončíte spolu s ním. Prípadne môžete spustenie a ukončenie MongoDB ovládať programovo.

MongoDB a C#

Keďže MongoDB je dokumentová databáza, bolo potrebné ukladané objekty previesť na dokumenty (MongoDB Document). Ovládač MongoDB pre .NET síce obsahuje možnosť ukladať priamo objekty ľubovoľného typu, nefunguje to však úplne spoľahlivo (občasný StackOverflow v mscore.lib).

Prevod objektov na MongoDB Document

Prevod ľubovoľnej triedy na dokument a jej nasledujúcu rekonštrukciu z dokumentu je možné jednoducho vykonať pomocou reflexie, nie je však možné ukladať ako položky dokumentu iné objekty. Ak nemôžete priamo zasahovať do definícií použitých tried môžete v C# použiť extension method alebo partial classes:

partial class AccountInTime {
  public Document ToDocument()
  {
      Document document = new Document(); document["_id"] = AccountId;
      Type accountInTimeType = this.GetType();
      PropertyInfo[] fieldInfo = accountInTimeType.GetProperties();
      string[] bannedProperties = {"User", "Account"};
      foreach (PropertyInfo info in fieldInfo) {
        if (!bannedProperties.Contains(info.Name))
        {
          document[info.Name] = info.GetValue(this, null);
        }
      }
    return document;
  }
      
  public AccountInTime(Document document) {
      Type accountInTimeType = this.GetType();
      PropertyInfo[] fieldInfo = accountInTimeType.GetProperties();
      foreach (PropertyInfo info in fieldInfo) {
        info.SetValue(this,document[info.Name],null);
      }
  }
}

Metóda ToDocument nastaví kľúč _id na vlastnosť AccountId, pomocou reflexie prejde všetky vlastnosti objektu (okrem explicitne zakázaných) a uloží ich do dokumentu. Konštruktor rovnako pomocou reflexie prejde všetky vlastnosti objektu a naplní ich hodnotami z dokumentu.

Práca s MongoDB

Práca so samotnou MongoDB može byť implementovaná napríklad pomocou Singleton triedy, ktorá vytvára spojenie s MongoDB:

internal sealed class MongoRepository
{
  private static MongoRepository _mongoRepository;

  public static MongoRepository GetInstance()
  {
    return _mongoRepository ?? (_mongoRepository = new MongoRepository());
  }
      
  private readonly Mongo _mongo = new Mongo();
      
  public MongoRepository() {
      
      _mongo = new Mongo();
      _mongo.Connect();
  }
}

Pri vkladaní záznamov do MongDB je potrebné získať referenciu na databázu, na požadovanú kolekciu a na vloženie dokument slúži metóda Insert:

public void Insert(IEnumerable<accountintime> accounts)
{
      
      //databáza
      var db = _mongo.GetDatabase("to2");
      
      //kolekcia
      var collection = db.GetCollection("accountintimes");
      
      //zmazanie všetkých záznamov
      collection.Remove(new Document() { });

      foreach (AccountInTime account in accounts)
      {
      //vloženie záznamu
      collection.Insert(account.ToDocument());
      }
      
}

Premenná db reprezentuje databázu a premenná collection „tabuľku“. Ak daná databáza alebo kolekcia neexistuje, automaticky sa vytvorí. Metóda collection.Remove() maže záznamy vyhovujúce poskytnutému selektoru, new Document() je univerzálny selektor, ktorému vyhovujú všetky záznamy. Napríklad na zmazanie záznamov s _id=123 by bol použitý selektor new Document(){_id=123}.

Prístup k záznamom uloženým v MongoDB je možný napríklad pomocou IEnumerable rozhrania vhodného na jednorazovú iteráciu:

public IEnumerable<document> AccountInTimes
{
      get {

      //databáza
      var db = _mongo.GetDatabase("to2");

      //kolecia
      var collection = db.GetCollection("accountintimes");

      //výber všetkých záznamov
      return collection.FindAll().Documents;
      }
}

V prípade potreby vyhľadania záznamu pomocou nejakého kľúča je možné použiť LINQ a nájdený záznam následne previesť naspäť na objekt pôvodného typu:

AccountInTime dbAccountInTime = new AccountInTime(mongoRepository.AccountInTimes.Where(l => l["_id"].ToString() == accountId.ToString()).SingleOrDefault());

Záver

Použité riešenie s MongoDB fungovalo a vyriešilo pôvodný problém. Prístup k záznamom v lokálnej MongoDB databáze bol síce pomalší ako prístup k záznamov pämati, bol však výrazne rýchlejši ako dopytovanie do vzdialenej MS SQL databázy. Ak budete niekedy potrebovať uložiť veľké množstvo prevažne plochých záznamov do štruktúry podobnej hash mape, určite siahnite po nejakej NoSQL databáze, oplatí sa to.

Igor Kulman

Igor Kulman

Je absolventom softvérového inžinierstva na MFF UK v Prahe a aktuálne pracuje ako Windows Phone 7 vývojár vo firme Inmite.

Školení: Hackujeme operační systém Android

 

Školení vám ukáže, jak se dostat k Linuxu (tzv. "rootování"), který se pod hezkou tváří Androida skrývá a jak ho naplno využít. Pomůže vám to při záloze dat, zvětšování prostoru pro aplikace nebo sdílení připojení k internetu a pokud chcete z telefonu dostat opravdové maximum, ukážeme vám, jak v něm vyměnit kompletní systém za lepší.

Podrobnější informace a přihláška

Přehled názorů

Rychlost
Tomáš Herceg 1. 3. 2011 08:43
Nový
└ 
Re: Rychlost
Igor Kulman 1. 3. 2011 10:11
Nový
 
└ 
Re: Rychlost
Logik 1. 3. 2011 12:48
Nový
 
 
└ 
Re: Rychlost
Igor Kulman 1. 3. 2011 15:13
Nový
 
 
 
└ 
Re: Rychlost
Roman Antoň 1. 3. 2011 17:26
Nový
MongoDB - XML
Petr Bíža 1. 3. 2011 09:22
Nový
└ 
Re: MongoDB - XML
ghjfghj 3. 3. 2011 20:33
Nový
Re: Praktické použitie MongoDB v .NET
Ladislav Thon 1. 3. 2011 18:48
Nový
Konzistence dat
Majkl 3. 3. 2011 11:50
Nový
Mono
ghjfghj 3. 3. 2011 20:35
Nový
└ 
Re: Mono
xor 16. 3. 2011 07:22
Nový
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem