Channels ▼
RSS

MongoDB with C#: Deep Dive


Add a new view, Details.cshtml, within the Views\Player subfolder:

@model RetrogamesWeb.Data.Entities.Player

@{
    ViewBag.Title = "Player's details";
}

<h2>Player's details</h2>

<fieldset>
    <legend>Player</legend>

    <div class="display-label">
        @Html.DisplayNameFor(model => model.Name)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Name)
    </div>

    <div class="display-label">
        @Html.DisplayNameFor(model => model.Gender)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Gender)
    </div>
</fieldset>

<table>
    <tr>
        <th>
            Game
        </th>
        <th>
            Date & Time
        </th>
        <th>
            Score
        </th>
    </tr>

@foreach (var score in Model.Scores) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => score.GameName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => score.ScoreDateTime)
        </td>
        <td>
            @Html.DisplayFor(modelItem => score.ScoreValue)
        </td>
    </tr>
}

</table>

<p>
    @Html.ActionLink("Play Games!", "PlayGames", new { id = Model.Id })
</p>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.Id })
    @Html.ActionLink("Back to List", "Index")
</p>

Add a new view, Edit.cshtml, within the Views\Player subfolder:

@using RetrogamesWeb.Data.Entities
@model RetrogamesWeb.Data.Entities.Player

@{
    ViewBag.Title = "Edit player";
}

<h2>Edit player</h2>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Player</legend>

        @Html.HiddenFor(model => model.Id)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
        
        <div class="editor-label">
            @Html.LabelFor(model => model.Gender)
        </div>
        <div class="editor-field">
            @Html.DropDownListFor(model => model.Gender, new SelectList(Enum.GetValues(typeof(Gender))))
            @Html.ValidationMessageFor(model => model.Gender)
        </div>
        
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Add a new view, Index.cshtml, within the Views\Player subfolder:

@model IEnumerable<RetrogamesWeb.Data.Entities.Player>

@{
    ViewBag.Title = "Players";
}

<h2>Players</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id = item.Id.ToString() }) |
            @Html.ActionLink("Details", "Details", new { id = item.Id.ToString() }) |
            @Html.ActionLink("Delete", "Delete", new { id = item.Id.ToString() })
        </td>
    </tr>
}

</table>

Add a new view, PlayGames.cshtml, within the Views\Player subfolder:

@model RetrogamesWeb.Models.PlayerGames

@{
    ViewBag.Title = "Play games";
}

<h2>Play games</h2>

<fieldset>
    <legend>Player</legend>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Player.Name)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Player.Name)
    </div>
</fieldset>

<h3>Click on the desired game and register your score</h3>

@foreach (var game in Model.AvailableGames)
{
    <p>
        @Html.ActionLink(game.Name, "AddScore", new { playerId = Model.Player.Id, gameId = game.Id, gameName = game.Name })
    </p>
}

<p>
    @Html.ActionLink("Back to List", "Index")
</p>

Working with the ASP.NET MVC Web Application

If you start your website and go to /Game/Create (http://localhost:16820/Game/Create, in my case), you can enter a name, date, select one or more categories, click Create (see Figure 6), and MongoDB will perform the following actions:

  • Create the new retrogamesweb database (the previous database created was retrogames).
  • Create the games collection in the new database.
  • Insert the new game document in the games collection.

As explained in the previous article, you will definitely want to create indexes based on the most frequent queries. Indexes are as important in MongoDB, as they are in any other database.

TCreating a new game
Figure 6: Creating a new game.

After you insert many game documents, you will see the list sorted by release date in descending order in /Game (see Figure 7). The time shouldn't appear in both the /Game/Create and /Game/Index views, but I didn't want to add annotations in the code for either UI hints or formatting. The data layer is the most important in this case.

Listing a maximum of 100 games
Figure 7: Listing a maximum of 100 games.

Similarly, go to /Player/Create, enter a name, select a gender from the dropdown list, click Create (see Figure 8) and MongoDB will perform the following actions:

  • Create the players collection in the retrogamesweb database.
  • Insert the new player document in the players collection.

Creating a new player
Figure 8: Creating a new player.

You will see the new player in the list. Click the Details link on the right-hand side of the player name and the /Player/Details view will display an empty scores list. Click the Play Games! link, and you will go to the Player/PlayGames view (see Figure 9); then click on the desired game to generate a random score.

The Player/PlayGames view
Figure 9: The Player/PlayGames view.

Click on the link for any game and the application will push a new random score to the player document. The browser will display the Player/Details view with the scores registered so far (see Figure 10). You can use MongoVUE or the MongoDB shell to see the changes in the database collections (see Figure 11).

The Player/Details view with many scores listed
Figure 10: The Player/Details view with many scores listed.

The player document with five score documents in the Scores array
Figure 11: The player document with five score documents in the Scores array.

You can use AJAX to retrieve and display the available games and the scores for a player. You can also add paging and search capabilities learning just a few additional things about MongoDB queries. Note that the embedded scores can become a big problem for this application, and it might be a better idea to create a specific collection for the scores to have more flexibility to query scores. However, the idea here is to provide an example with embedded documents, so that you know specific operations to work with them and their most common problems. For example, the generic GetById method has a problem with embedded documents because you retrieve all of them each time you call this method. Thus, you must be careful when deciding what to save in each document.

In this example, the score was important and the write operations required the acknowledged option. However, when you want the best possible performance for applications that require logging huge amounts of data and you can lose some data because it doesn't add too much value, you should work with the unacknowledged option.

For example, if you want to do sampling, you can define a capped array for the scores to make sure the number of saved scores won't be excessive, and then discard scores when you reach the limit.

I've provided many examples of MongoDB working with the C# driver in a console application and in an ASP.NET MVC Web application. However, MongoDB has an important number of additional features and advantages that I haven't covered in this series. I also haven't covered database-administration related topics, such as the different scalability options. But with the foothold I've provided, you can dive deeper on more advanced features, such as the use of MapReduce and more complex queries. You won't regret investing time in learning MongoDB features.


Gaston Hillar is an expert in Windows-based programming who writes frequently for Dr. Dobb's.


Related Articles

Getting Started with MongoDB

MongoDB with C#


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video