Chapter 2. Mongo DB CRUD and Mongo Shell – Part One

2. CRUD and Mongo Shell

MongoDBCRUD which stands for an operation of creating, read, update, and delete documents.

In Mongo DB, we called these operations in different names:

Create – Insert
Read – Find
Update – Update
Delete – Remove

All of these operations are function-based methods, which means that Mongo DB’s CRUD operations exist as methods/functions in programming language APIs, not as a separate language like T-SQL.

2.1 Create Operations

Create or insert operations add new documents to a collection. The MongoDB provides the following methods:

  • db.collection.insert()
  • db.collection.insertOne() new in version 3.2
  • db.collection.insertMany() new in version 3.2

In MongoDB, insert operations target a single collection. All write operations in MongoDB are atomic on the level of a single document

For more information on atomicity, transaction and concurrency control will be discussed in later chapters.

insert

In the new version 3.2, there are two functions are added – insertOne() and insertMany(). What’s the differences between three of these functions?

Behavior

If the collection does not exist, insert operations will create the collection.

Returns

Insert(): returns a WriteResult object, like WriteResult({“nInserted”: 1 }). The nInserted field specifies the number of documents added. If the operation encounters an error, the WriteResult object will contain the error information.

InsertOne(): returns a document with the status of the operation:

{
    "acknowledged": true,
    "insertedId": ObjectId("5742045ecacf0ba0c3fa82b0")
}

InsertMany(): returns a document with the status of the operation:

{
    "acknowledged" : true,
    "insertedIds" : [
        ObjectId("57420d48cacf0ba0c3fa82b1"),
        ObjectId("57420d48cacf0ba0c3fa82b2"),
        ObjectId("57420d48cacf0ba0c3fa82b3")
    ]
}

2.2 Query Documents

Query Method

  • db.collection.findOne()
  • db.collection.find() this method returns a cursor to the matching document.

db.collection.find(<query filter>, <projection>)

Return only one document

If we just want to get one document from your collection. db.collection.findOne() is the best choice.

findOne

Select All Document in a Collection

db.collection.find({}) or db.collection.find()

Specify Query Filter Conditions

Specify Equality Condition

<field> : <value> expressions are used to select all documents that contain the <field> with the specified <value>:

{<field1> : <value1>, <field2> : <value2>, …}

Specify Conditions Using Query Operators

A query filter document can use the query operators to specify conditions in the following form:

{ <field1>: { <operator1>: <value1> }, … }

$in : Either … Or … operator (comparison operators)

collection.find

OR Conditions

$or : a logical OR conjunction so that the query selects the documents in the collection that match at least one condition.

orCondition

AND Conditions

Implicitly, a logical AND combination connects the clauses of a compound query so that the query selects the documents in the collection that match all the conditions.

andCondition

Specify AND as well as OR Conditions

and_orCondition

Using regex and $exists

$exists

exists

$regex

regex

Query on Embedded Documents

When the field holds an embedded document, a query can either specify an exact match on the embedded document or specify a match by individual fields in the embedded document using the dot notation.

db.users.find( { favorites: { artist: &amp;quot;Picasso&amp;quot;, food: &amp;quot;pizza&amp;quot; } } )
db.users.find( { &amp;quot;favorites.artist&amp;quot;: &amp;quot;Picasso&amp;quot; } )

Query on Arrays

When the field holds an array, you can query for an exact array match or for specific values in the array. If the array holds embedded documents, you can query for specific fields in the embedded documents using dot notation.

If you specify multiple conditions using the $elemMatch operator, the array must contain at least one element that satisfies all the conditions.

Entity Framework: Database Mappings – Chapter 4

Using Conventions and Configurations for Database Mappings

So far we have discussed the Code First convention and configurations that affect property attributes and those that pertain to relationships between classes. In both of these categories, Code First affected not only the model but the database as well. In this chapter, we will focus on how to map classes to the database without impacting the conceptual model.

Mapping Class Name to Database Table and Schema Name

Entity Framework use its pluralization service to infer database table names based on the class names in the model. Destination, for example, becomes Destinations, Person becomes to People, etc. The class name of model, however, might not be the same as the table naming conventions.

We can use the Table Data Annotation to ensure that Code First maps your class to the correct table name. Additional we also could assign the schema to the table (default is dbo).

Configuring Table and Schema Name with Data Annotations

The Table Data Annotation allows us to change the name of the table that our model class maps to.

[Table("PersonPhotos")]
public class PersonPhoto

[Table("Locations", Schema="baga")]
public class Destination

TableConfiguration Figure: Table configuration results in baga.Locations

Configuring Table and Schema name with the Fluent API


modelBuilder.Entity<Destination>().ToTable("Locations", "baga");

Mapping Property names to Database Columns

Not only we can remap the table name, but we can also alter the presumed database column name. By convention, Code First will use the name of the property as the name of the column that it maps to, but this may not always the case.

Modifying the Default Column Name with Data Annotations

[Column("LocationID")]
public int DestinationId { get; set; }
[Required, Column("LocationName")]
public string Name { get; set; }

Modifying the Default Column Name with the Fluent API

HasColumnName is the Fluent method used to specify a column name for a property.

public class DestinationConfiguration :
EntityTypeConfiguration<Destination>
{
  public DestinationConfiguration()
  {
    Property(d => d.Nam
      .IsRequired().HasColumnName("LocationName");
    Property(d => d.DestinationId).HasColumnName("LocationID");
  }
}

Affecting Column Names for Complex Types

In the Chapter 1, we discussed the ComplexType from the Address class. Code First will map this class into database by using the pattern Address_StreetAddress or Address_State, etc.
We can rename these column names like this:

//Data Annotation
[ComplexType]
public class Address
{
  public int AddressId { get; set; }
  [MaxLength(150)]
  [Column("StreetAddress")]
  public string StreetAddress { get; set; }
  [Column("City")]
  public string City { get; set; }
  [Column("State")]
  public string State { get; set; }
  [Column("ZipCode")]
  public string ZipCode { get; set; }
}
//Fluent API
public class AddressConfiguration : ComplexTypeConfiguration<Address>
{
  public AddressConfiguration()
  {
    Property(a => a.StreetAddress).HasColumnName("StreetAddress");
  }
}

Allowing Multiple Entities to Map to a Single Table: aka Table Splitting

Often a database table has so many columns in it that some scenarios only require you to use a subset of them, while others require access to additional column data. Table splitting helps solve this problem by allowing us to break up the columns of a single table across multiple entities.

You may be more likely to want table splitting when mapping to an existing database where you find yourself with the scenario described above, though you might find that you want it even when letting Code First create the database for you.

Example: The PersonPhoto calss with Data Annotation

[Table("PersonPhotos")]
public class PersonPhoto
{
  [Key , ForeignKey("PhotoOf")]
  public int PersonId { get; set; }
  [Column(TypeName="image")]
  public byte[] Photo { get; set; }
  public string Caption { get; set; }
  public Person PhotoOf { get; set; }
}

In order to map entities into a common table, the entities must comply with the following rules:

  • The entities must have a one-to-one relationship.
  • The entities must share a common key.

The Person and PersonTable classes meet these requirements.

Mapping to a Common Table using Data Annotations

We’ll apply the table name to both classes:

[Table("People")]
public class Person
[Table("People")]
public class PersonPhoto

PeopleTable
What’s more interesting about his mapping is that we can query one of the entities without wasting resources pulling back the whole table columns (including the columns are in the other entity).
If we execute a query against the Person class, like context.People.ToList(), Entity Framework only projects those clolumns that map to the Person class.

Splitting a Table Using the Fluent API

We can easily add them in the relevant EntityTypeConfiguration class:

modelBuilder.Entity<Person>().ToTable("People");
modelBuilder.Entity<PersonPhoto>().ToTable("People");

About Lazy Loading Split Table Data

Lazy loading makes this feature shine. Although the DbContext we are using has lazy loading enabled by default. Any navigation property with the virtual keyword applied to it will automatically be retrieved from the database when it is first accessed. For instance:

[Required]
public virtual PersonPhoto Photo { get; set; }

Lazy loading Photo

var people = context.People.ToList();
var firstPerson = people[0];
SomeCustomMethodToDisplay(firstPerson.Photo.Caption);

Once we enable the lazy loading, the Entity Framework will run a behind-the-scenes query when we try to retrieve the null data from database. If we disable it, the last line of code will throw an exception because the Photo property will be null.

Mapping a Single Entity Across Multiple Tables

<strong><em>Example:DestinationConfiguration with Entity Splitting mapping at the end</em></strong>
public class DestinationConfiguration :
EntityTypeConfiguration<Destination>
{
  public DestinationConfiguration()
  {
    Property(d => d.Name)
      .IsRequired().HasColumnName("LocationName");
    Property(d => d.DestinationId).HasColumnName("LocationID");
    Property(d => d.Description).HasMaxLength(500);
    Property(d => d.Photo).HasColumnType("image");
   
    // ToTable("Locations", "baga");
    Map(m =>
    {
      m.Properties(d => new {d.Name, d.Country, d.Description});
      m.ToTable("Locations");
    });
    Map(m =>
    {
      m.Properties(d => new { d.Photo });
      m.ToTable("LocationPhotos");
    });
  }
}

DestinationMapsTwoTable
Example: Insert a single object that maps to two database tables

private static void InsertDestination()
{
  var destination = new Destination
  {
    Country = "Indonesia",
    Description = "EcoTourism at its best in exquisite Bali",
    Name = "Bali"
  };
  using (var context = new BreakAwayContext())
  {
    context.Destinations.Add(destination);
    context.SaveChanges();
  }
}

Preventing Types from Being Included in the Model

Using Data Annotation to ignore types

[NotMapped]
public class MyInMemoryOnlyClass

Using Fluent Configuration to ignore types

modelBuilder.Ignore<MyInMemoryOnlyClass>();

Understanding Property Mapping and Accessibility

The list of rules will explain when defining properties in your classes, what to expect from convention, and how to change the default mapping with configuration.

Scalar Property Mapping

Scalar properties are only mapped if they can be converted to a type that is supported by EDM.
The valid EDM types are Binary, Boolean, Byte, DateTime, DateTimeOffset, Decimal, Double, Guid, Int16, Int32, Int64, SByte, Single, String, Time.
Scalar properties that can’t be mapped to an EDM type are ignored (e.g., enums and unsigned integers).

Accessibility of Properties, Getters, and Setters

  1. A public property will be automatically mapped by Code First.
  2. The setter can be marked with a more restrictive accessor, but the getter must remain public for the property to be mapped automatically.
  3. A nonpublic property must be configured using the Fluent API in order to be mapped by Code First.

Mapping Inheritance Hierarchies

Entity Framework supports a variety of inheritance hierarchies in the model.

Working with Code First’s Default Inheritance: Table Per Hierarchy (TPH)

Table Per Hierarchy (TPH) describes mapping inherited types to a single database table that uses a discriminator column to differentiate one subtype from another.
Example: Lodging class and new Resort class that derives from Loding

public class Lodging
{
  public int LodgingId { get; set; }
  [Required]
  [MaxLength(200)]
  [MinLength(10)]
  public string Name { get; set; }
  public string Owner { get; set; }

  // public bool IsResort { get; set; }
  public decimal MilesFromNearestAirport { get; set; }
  [InverseProperty("PrimaryContactFor")]
  public Person PrimaryContact { get; set; }
  [InverseProperty("SecondaryContactFor")]
  public Person SecondaryContact { get; set; }
  public int DestinationId { get; set; }
  public Destination Destination { get; set; }
  public List<InternetSpecial> InternetSpecials { get; set; }
}
public class Resort : Lodging
{
  public string Entertainment { get; set; }
  public string Activities { get; set; }
}

Resort type field in Loging table
The Resort information is stored in the Lodgings tables, and Code First established a column called Discriminator. This property is non-nullable and its type is nvarchar(128). By default, Code First will use the type name of each type in the hierarchy as the value stored in the discriminator column.
If we run the code below, the Entity Framework will insert the string “Resort” into the Discriminator column in the database.

private static void InsertResort()
{
  var resort = new Resort {
  Name = "Top Notch Resort and Spa",
  MilesFromNearestAirport=30,
  Activities="Spa, Hiking, Skiing, Ballooning",
  Destination=new Destination{
  Name="Stowe, Vermont",
  Country="USA"}
  };
  using (var context = new BreakAwayContext())
  {
    context.Lodgings.Add(resort);
    context.SaveChanges();
  }
}

Customizing the TPH Discriminator Field with the Fluent API

Configuring the discriminator column name and possible values.

Map(m =>
{
  m.ToTable("Lodgings");
  m.Requires("LodgingType").HasValue("Standard");
})
.Map<Resort>(m =>
{
  m.Requires("LodgingType").HasValue("Resort");
});

Configuring Table Per Type (TPT) Hierarchy

While TPH contains all of the types for a hierarchy in a single table, Table Per Type(TPT) only stores properties from the base class in a single table. Additional properties defined on a derived type are stored in a separate table with a foreign key back to the core table.

For instance:
Mapping ToTable for a TPT inheritance from base entity

public class Resort : Lodging
{
  public string Entertainment { get; set; }
  public string Activities { get; set; }
}

modelBuilder.Entity<Lodging>().Map(m =>
  {
    m.ToTable("Lodgings");
    }).Map<Resort>(m =>
  {
    m.ToTable("Resorts");
});

Configuring for Table Per Concrete Type (TPC) Inheritance

Table Per Concrete Type (TPC) is similar to TPT, except that all the properties for each type are stored in separate tables. There is no core table that contains data common to all types in the hierarchy. This allows you to map an inheritance hierarchy to tables with overlapping (common) fields. This can be useful when you set ancient data aside in a spare table.

TPC mapping is configured using the MapInheritedProperties method, which is only
accessible from within the Map method. And since we also need a separate table for the derived class (that will be duplicating the inherited properties), we can combine the Table configuration and the MapInheritedProperties configuration.

modelBuilder.Entity<Lodging>()
  .Map(m =>
  {
    m.ToTable("Lodgings");
  })
  .Map<Resort>(m =>
  {
    m.ToTable("Resorts");
    m.MapInheritedProperties();
  });

Tip:How to choose an Inheritance Strategy

Working with Abstract Base Classes

if we modify the Lodging class to be an abstract base class. That means we’ll never use this class directly. It cannot be instantiated. Instead, we ill only derive from it. Thus, we add a second derived class: Hostel

abstract public class Lodging
{
  public int LodgingId { get; set; }
  public string Name { get; set; }
  public string Owner { get; set; }
  public decimal MilesFromNearestAirport { get; set; }
  public List<InternetSpecial> InternetSpecials { get; set; }
  public Nullable<int> PrimaryContactId { get; set; }
  public Person PrimaryContact { get; set; }
  public Nullable<int> SecondaryContactId { get; set; }
  public Person SecondaryContact { get; set; }
  public int DestinationId { get; set; }
  public Destination Destination { get; set; }
}
public class Resort : Lodging
{
  public string Entertainment { get; set; }
  public string Activities { get; set; }
}
public class Hostel: Lodging
{
  public int MaxPersonsPerRoom { get; set; }
  public bool PrivateRoomsAvailable { get; set; }
}

Code First convention, which means that the inheritance will revert to TPH. All of the fields from the derived classes are contained in the Lodgings table.

Entity Framework: Relationship Configuration – Chapter 3

Using Convention and Configuration for Relationships

In the last chapter, we discussed about the convention and configuration for properties by using Data Annotation and Fluent API.

If we define both classes a reference and a collection navigation property, by convention it will configure this as a one-to-many relationship. For example:

public class Destination
{
    public int DestinationId { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }
    public string Description { get; set; }
    public byte[] Photo { get; set; }
    public List<Lodging> Lodgings { get; set; }
}


public class Lodging
{
    public int LodgingId { get; set; }
    public string Name { get; set; }
    public string Owner { get; set; }
    public bool IsResort { get; set; }
    public decimal MilesFromNearestAirport { get; set; }
    public Destination Destination { get; set; }
}
modelBuilder.Entity<Destination>()
    .HasMany(d => d.Lodgings)
    .WithOptional(l => l.Destination);

Code First has worked out the model and its relationships, Entity Framework will treat those relationships just the same as it does with POCOs that are mapped using an EDMX file.

Working with Multiplicity

Code First applies a set of rules to work out the multiplicity of each relationship. The rules use the navigation properties you defined in your classes to determine multiplicity.

  • If your classes contain a reference and a collection navigation property, Code First assumes a one-to-many relationship.
  • Code First will also assume a one-to-many relationship if your classes include a navigation property on only one side of the relationship (i.e., either the collection or the reference, but not both).
  • If your classes include two collection properties, Code First will use a many-to-many relationship by default.
  • If your classes include two reference properties, Code First will assume a one-to-one relationship.
  • In the case of one-to-one relationships, you will need to provide some additional information so that Code First knows which entity is the principal and which is the dependent.
  • when we define a foreign key property in your classes, Code First uses the nullability of that property to determine if the relationship is required or optional.

Configuring Multiplicity with Data Annotations

Most of the multiplicity configuration needs to be done using the Fluent API. But we can use Data Annotations to specify that a relationship is required.

public class Lodging
{
  public int LodgingId { get; set; }
  public string Name { get; set; }
  public string Owner { get; set; }
  public bool IsResort { get; set; }
  public decimal MilesFromNearestAirport { get; set; }

  [Required]
  public Destination Destination { get; set; }
}

If we run the application, the database gets recreated with the change.
微信截图_20150806224846
Configuring Multiplicity with the Fluent API

The Fluent API is very different with the Data Annotations, where we are literally configuring the relationship, not property. Sometimes it’s enough to mention one end, but most often we need to describe the complete relationship.

To identify a relationship, you point to its navigation properties. Regardless of which
end you begin with, this is the pattern:

Entity.Has[Multiplicity](Property).With[Multiplicity](Property)

The multiplicity can be Optional (a property that can have a single instance or be null),
Required (a property that must have a single instance), or Many (a property with a collection of a single type).

The Has methods are as follows:

  • HasOptional
  • HasRequired
  • HasMany

In most cases you will follow the Has method with one of the following With methods:

  • WithOptional
  • WithRequired
  • WithMany

Example: One-to-Many relationship

modelBuilder.Entity<Destination>()
    .HasMany(d =>d.Lodgings)
    .WithOptional(l =>l.Destination);

EF One to Many Relationship

Notice: If we try to configuring a one-to-one relationship where both ends are
required or both ends are optional, Code First will need some more information from you to work out which end is the principal and which end is the dependent. We will discuss this later.

Work with Foreign Key

In previous section, we add a required public Destination Destination { get; set; } in the Lodging class. But now, we remove the configuration from Lodging class, replace it to:

 
public int DestinationId { get; set; }

Code First has automatically detected that DestinationId is a foreign key for the Lodging to Destination relationship and is no longer generating the Destination_DestinationId foreign
key.FK add to Class

The foreign key property will be discovered by convention if it is named [Target Type Key Name], [Target Type Name] + [Target Type Key Name], or [Navigation Property Name] + [Target Type Key Name].

Specifying Unconventionally Named Foreign Keys

What happens when we use a foreign key that does not follow the Code First convention?

Example: Internet Special class

namespace Domain.Entity
{
    public class InternetSpecial
    {
        public int InternetSpecialId { get; set; }
        public int Nights { get; set; }
        public decimal CostUSD { get; set; }
        public DateTime FromDate { get; set; }
        public DateTime ToDate { get; set; }
        public int AccommodationId { get; set; }
        public Lodging Accommodation { get; set; }
    }

    public class Lodging
    {
        public int LodgingId { get; set; }
        public string Name { get; set; }
        public string Owner { get; set; }
        public bool IsResort { get; set; }
        public decimal MilesFromNearestAirport { get; set; }

        [Required]
        public Destination Destination { get; set; }
        public List<InternetSpecial>InternetSpecials { get; set; }
    }

    public class Destination
    {
        public int DestinationId { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }
        public string Description { get; set; }
        public byte[] Photo { get; set; }
        public List<Lodging> Lodgings { get; set; }
    }
}

Fluent API: Foreign Key Configuration

namespace Domain.ModelConfiguration
{
    public class InternetSpecialConfiguration:EntityTypeConfiguration<InternetSpecial>
    {
        public InternetSpecialConfiguration()
        {
            HasRequired(s => s.Accommodation)
                .WithMany(l=>l.InternetSpecials)
                .HasForeignKey(s=>s.AccommodationId);

        }
    }
}

We could use the Data Annotation to configure the Foreign Key properties. For example:

[ForeignKey("Accommodation")]
public int AccommodationId { get; set; }
public Lodging Accommodation { get; set; }

In addition we recommend to use the Fluent API to specify the relationship.

Working with Inverse Navigation Properties

So far Code First has always been able to work out that the two navigation properties we have defined on each end of a relationship are in fact different ends of the same relationship. However, this does not work on Many-to-Many relationship. In these case, Code First won’t be able to work out which navigation properties match up. So we will need to provide some additional configuration.

For example, we need to track two contracts for each lodging.

using System;
using System.Collections.Generic;
using Microsoft.Build.Framework;

namespace Business
{
    public class Lodging
    {
        public int LodgingId { get; set; }
        public string Name { get; set; }
        public string Owner { get; set; }
        public bool IsResort { get; set; }
        public decimal MilesFromNearestAirport { get; set; }
        [Required]
        public Destination Destination { get; set; }

        public Person PrimaryContract { get; set; }
        public Person SecondaryContract { get; set; }
    }

    public class Destination
    {
        public int DestinationId { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }
        public string Description { get; set; }
        public byte[] Photo { get; set; }
        public List<Lodging> Lodgings { get; set; }
    }

    public class Person
    {
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime Birthday { get; set; }

        public List<Lodging> PrimaryContractFor { get; set; }
        public List<Lodging> SecondaryContractFor { get; set; }
    }
}

Code First conventions will make the wrong assumptions about these new relationships. Because there are two sets of navigation properties, Code First is unable to work out how they match up. In this case, Code First will create a separate relationship for each property.
TooManyForeignKeysFigure: Too many foreign key in the Lodings table

We can add configuration (using Data Annotations or the Fluent API) to present this information to the model builder.

Data Annotation:

[InverseProperty("PrimaryContactFor")]
public Person PrimaryContact { get; set; }
[InverseProperty("SecondaryContactFor")]
public Person SecondaryContact { get; set; }

Or Fluent API:

modelBuilder.Entity<Lodging>()
    .HasOptional(l => l.PrimaryContact)
    .WithMany(p => p.PrimaryContactFor);

modelBuilder.Entity<Lodging>()
    .HasOptional(l => l.SecondaryContact)
    .WithMany(p => p.SecondaryContactFor);

Working with Cascade Delete

Cascade delete allows dependent data to be automatically deleted when the principal record is deleted. If we delete a Destination, for example, the related Lodgings will also be deleted automatically. Entity Framework supports cascade delete behavior for inmemory data as well as in the database.

When a cascade delete is defined, Code First will also configure a cascade delete in the database that it creates.But, We could turn it off via Fluent API. For example:

HasRequired(l=>l.Destination)
    .WithMany(d=>d.Lodgings)
    .WillCascadeOnDelete(false)

Exploring Many-to-Many Relationships

In order to achieve a many to many relation in the database, we need to establish a relation table which will hold the primary key from every table in the many to many relation. Here is an example of a simple many to many relation that can exist in a database:

ManytoMany ActivityTripsActivityTrips

Example: Activity class, Trip class and Many-to-Many relationship class

namespace Model
{
    public class Activity
    {
        public Activity()
        {
            Trips = new List<Trip>();
        }
        public int ActivityId { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Trip> Trips { get; set; }
    }

    public class Trip
    {
        public Trip()
        {
            Activities = new List<Activity>();
        }
        public Guid Identifier { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        public decimal CostUSD { get; set; }
        public byte[] Timestamp { get; set; }

        public virtual ICollection<Activity> Activities { get; set; }
    }

    public class ActivityTrip
    {
        public int ActivityId { get; set; }
        public Guid Identifier { get; set; }
    }
}

Entity Type Configuration:

public class ActivityConfiguration:EntityTypeConfiguration<Activity>
    {
        public ActivityConfiguration()
        {
            //Key
            HasKey(k => k.ActivityId);

            //Property
            Property(p => p.Name)
                .IsRequired()
                .HasMaxLength(50)
                .HasColumnType("nvchart");

            //Table
            ToTable("Activity");

            //Relationship
            HasMany(d=>d.Trips)
                .WithMany(l=>l.Activities)
                .Map(m=>
                {
                    m.MapLeftKey("ActivityId");
                    m.MapRightKey("Identifier");
                    m.ToTable("ActivityTrip");
                });
        }
    }

Working with Relationships that Have Unidirectional Navigation

So far we have looked at relationships where a navigation property is defined in both classes that are involved in the relationship. However, this isn’t a requirement when working with the Entity Framework.
If we remove the the foreign key property from the Lodging class, and then change the name of the foreign key property, as shown below:

public class Lodging
    {
        public int LodgingId { get; set; }
        public string Name { get; set; }
        public string Owner { get; set; }
        public bool IsResort { get; set; }
        public decimal MilesFromNearestAirport { get; set; }

        public int LocationId { get; set; }
        //public int DestinationId { get; set; }
        //public Destination Destination { get; set; }
        public List<InternetSpecial> InternetSpecials { get; set; }
        public Person PrimaryContact { get; set; }
        public Person SecondaryContact { get; set; }
    }

Next step, we configure the Lodging class with Fluent API. The Fluent API caters to relationships that only have one navigation property. The Has part of the configuration must specify a navigation property, but the With part can be left empty if there is no inverse navigation property.

modelBuilder.Entity<Destination>()
  .HasMany(d => d.Lodgings)
  .WithRequired()
  .HasForeignKey(l => l.LocationId);

Working with One-to-One Relationships

When we define a one-to-one relationship in our model,we need to use a reference navigation property in each class. When configuring one-to-one relationships, Entity Framework requires that the primary key of the dependent also be the foreign key. For instance:

public class PersonPhoto
{
  [Key]
  [ForeignKey("PhotoOf")]
  public int PersonId { get; set; }
  public byte[] Photo { get; set; }
  public string Caption { get; set; }
  public Person PhotoOf { get; set; }
}

public class Person
{
  [Key]
  public int SocialSecurityNumber { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }

  [Required]
  public PersonPhoto Photo { get; set; }
}

Configuring One-to-One Relationship with Fluent API

When we configure the relationship via Fluent API, we do not need to let Code First know which class is principle and which class is dependent.
We start with HasRequired, and then we will have the optional options like WithRequiredPrincipal and WithRequiredDependent. For example, if we want to configure the PersonPhoto, which should be the dependent:

modelBuilder.Entity<PersonPhoto>()
  .HasRequired(p => p.PhotoOf)
  .WithRequiredDependent(p => p.Photo);

Using concurrent collections

When working in a multi-threaded environment, we need to make sure that we are not manipulating shared data at the same time without synchronizing access.

The .NET framework offers some collection class that are created specifically for use in concurrent environments. These collections are thread-safe, which means that they internally use synchronization to make sure that they can be accessed by multiple threads at the same time.

Those collections are the following:

  • BlockingCollection<T>
  • ConcurrentBag<T>
  • ConcurrentDictionary<TKey, T>
  • ConcurrentQueue<T>
  • ConcurrentStack<T>

BlockingCollection<T>

This collection is thread-safe for adding and removing data. Removing an item from the collection can be blocked until data becomes available. Adding data is fast, but you can set a maximum upper limit. If that limit is reached, adding an item blocks the calling thread until there is room.

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using static System.String;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            var col = new BlockingCollection<string>();
            Task read = Task.Run(() =>
            {
                while (true)
                {
                    Console.WriteLine(col.Take());
                }
            });

            Task write = Task.Run(() =>
            {
                while (true)
                {
                    string s = Console.ReadLine();
                    if (IsNullOrWhiteSpace(s)) break;
                    col.Add(s);
                }
            });

            write.Wait();
        }

         
    }
}

ConcurrentBag

A ConcurrentBag is just a bag of items. It enables duplicates and it has no particular order. Important methods are Add, TryTake, and TryPeek. One thing we should bear in mind is that the TryPeek method is not very useful in a multi-threaded environment.

Example Using a concurrentStack

using System;
using System.Collections.Concurrent;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            var bag = new ConcurrentBag<int> {99, 45, 56, 88};

            int result;

            if (bag.TryTake(out result))
            {
                Console.WriteLine(result); //88
            }

            if (bag.TryPeek(out result))
                Console.WriteLine("there is a next item: {0}",result); //56

            Console.ReadKey();
        }
    }
}

ConcurrentStack and ConcurrentQueue

A stack is a last in, first out (LIFO) collection. A queue is a first in, first out (FIFO) collection.

ConcurrentStack has two important methods: Push and TryPop. Push is used to add an item to the stack; TryPop tries to get an item off the stack. We can never be sure whether there are items on the stack because multiple threads might be accessing your collection at the same time. We can also add and remove multiple items at once by using PushRange and TryPopRange. When we enumerate the collection, a snapshot is taken.

ConcurrentQueue offers the methods Enqueue and TryDequeue to add and remove items from the collection. It also has a TryPeek method and it implements IEnumerable by making a snapshot of the data.

ConcurrentDictionary

A ConcurrentDictionary stores key and value pairs in a thread-safe manner. You can use methods to add and remove items, and to update items in place if they exist.

When working with a ConcurrentDictionary you have methods that can atomically add, get, and update items. An atomic operation means that it will be started and finished as a single step without other threads interfering. TryUpdate checks to see whether the current value is equal to the existing value before updating it. AddOrUpdate makes sure an item is added if it’s not there, and updated to a new value if it is. GetOrAdd gets the current value of an item if it’s available; if not, it adds the new value by using a factory method.

Using async and await

Why we need asynchronous programming

When our application is executing an I/ O operation on the primary application thread, Windows notices that the thread is waiting for the I/ O operation to complete. Maybe we are trying to access some files on disk or over the network, and this could take some time.

Because of this, Windows pauses the thread so that it doesn’t use any CPU resources. But while doing this, it still uses memory, and the thread can’t be used to serve other requests, which in turn will lead to new threads being created if requests come in.

In order to solve this issue, we need to use the asynchronous code.  Instead of blocking your thread until the I/ O operation finishes, you get back a Task object that represents the result of the asynchronous operation. By setting a continuation on this Task, we can continue when the I/ O is done. In the meantime, thread is available for other work. When the I/ O operation finishes, Windows notifies the run-time and the continuation Task is scheduled on the thread pool.

async and await

Modern asynchronous .NET applications use two keywords: async and await. The async keyword is added to a method declaration, and its primary purpose is to enable the await keyword within that method (the keywords were introduced as a pair for backward-compatibility reasons). An async method should return Task<T> if it returns a value, or Task if it does not return a value.

Notice: Avoid async should only be used within an async event handler.

The following table shows typical areas where asynchronous programming improves responsiveness. The listed APIs from the .NET Framework 4.5 and the Windows Runtime contain methods that support async programming.

Application area Supporting APIs that contain async methods
Web access HttpClient , SyndicationClient
Working with files StorageFile, StreamWriter, StreamReader, XmlReader
Working with images MediaCapture, BitmapEncoder, BitmapDecoder
WCF programming Synchronous and Asynchronous Operations
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            var getResult = DownloadContent().Result;
            Console.WriteLine(getResult);
            Console.ReadKey();
        }

        public static async Task<string> DownloadContent()
        {
            using (var client = new HttpClient())
            {
                var result = await client.GetStringAsync("http://www.microsfot.com");
                return result;
            }
        } 
    }
}

Using the Parallel Class

The System.Threading.Tasks namespace also contains another class that can be used for parallel processing. The Parallel class has a couple of static methods— For, ForEach, and Invoke.

Parallelism involves taking a certain task and splitting it into a set of related tasks that can be executed concurrently. This also means that we can use the Parallel class only when our code doesn’t have to be executed sequentially.

Increasing performance with parallel processing happens only when you have a lot of work to be done that can be executed in parallel. The syntax of the Parallel.For shows below:

Parallel.For(int fromInclusive, 
             int toExclusive, 
             Action<int> body);

int n = ...
Parallel.For(0, n, i =>
{
   // ... 
});

Example Using Parallel.For and Parallel.For

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      long totalSize = 0;

      String[] args = Environment.GetCommandLineArgs();
      if (args.Length == 1) {
         Console.WriteLine("There are no command line arguments.");
         return;
      }
      if (! Directory.Exists(args[1])) {
         Console.WriteLine("The directory does not exist.");
         return;
      }

      String[] files = Directory.GetFiles(args[1]);
      Parallel.For(0, files.Length,
                   index =>; { FileInfo fi = new FileInfo(files[index]);
                              long size = fi.Length;
                              Interlocked.Add(ref totalSize, size);
                   } );
      Console.WriteLine("Directory '{0}':", args[1]);
      Console.WriteLine("{0:N0} files, {1:N0} bytes", files.Length, totalSize);
   }
}
// The example displaysoutput like the following: 
//       Directory 'c:\windows\': 
//       32 files, 6,587,222 bytes
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
 
namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var nums = Enumerable.Range(0, 1000000).ToArray();
            long total = 0;
 
            Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) =>
            {
                subtotal += nums[j];
                return subtotal;
            },
                (x) =>; Interlocked.Add(ref total, x));
 
            Console.WriteLine("The total is {0:N0}", total);
            Console.WriteLine("press any key to exit");
            Console.ReadKey();
        }
    }
}

Example Using Parallel.ForEach method

using System;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;

 class Test
 {
     static void Main()
     {
         int[] nums = Enumerable.Range(0, 1000000).ToArray();
         long total = 0;

         // First type parameter is the type of the source elements 
         // Second type parameter is the type of the thread-local variable (partition subtotal)
         Parallel.ForEach<int, long>(nums, // source collection
                                     () => 0, // method to initialize the local variable
                                     (j, loop, subtotal) => // method invoked by the loop on each iteration
                                     {
                                         subtotal += j; //modify local variable 
                                         return subtotal; // value to be passed to next iteration
                                     },
             // Method to be executed when each partition has completed. 
             // finalResult is the final value of subtotal for a particular partition.
                                     (finalResult) => Interlocked.Add(ref total, finalResult)
                                     );

         Console.WriteLine("The total from Parallel.ForEach is {0:N0}", total);
    }
}
// The example displays the following output: 
//        The total from Parallel.ForEach is 499,999,500,000

We can cancel the loop by using the ParallelLoopSate object. There are two options: Break and Stop. Break ensure that all iterations that are currently running will be finished. Stop just terminates everything. When breaking the parallel loop, the result variable has an IsCompleted value of false and a LowestBreakIteration of 500. When you use the Stop method, the LowestBreakIteration is null.

Chapter 1.1 Implement multi-threading and asynchronous processing

Objective Covers

Understanding Thread

A Thread is a small set of executable instructions, which can be used to isolate a task from a process. Multiple threads are efficient way to obtain parallelism of hardware and give interactive user interaction to your applications.

In current versions of Windows, each application runs in its own process. A process isolates an application from other applications by giving it own virtual memory and by ensuring that different processes can’t influence each other. Meanwhile, each process runs in its own thread. Windows must manage all of the threads to ensure they can do their work. Each thread is allowed by Windows to execute for certain time period. After this period ends, the thread is paused and Windows switches to another thread. This is called context switching. The current thread is using a certain area of memory; it uses CPU registers and other state data, and Windows has to make sure that the whole context of the thread is saved and restored on each switch. Thus, using threads does ensure that each process gets its time to execute without having to wait until all other operations finish. Today, the devices that we use have multiple cores. To make use of all these cores, we need multiple threads. Windows ensures that those threads are distributed over your available cores.

Using the Thread class

The Thread class can be found in the System.Threading namespace. This class enables you to create new treads, manage their priority, and get their status.  When using the Thread class we have control over all configuration options. We can, for example, specify the priority of our thread, tell Windows that our thread is long running, or configure other advanced options.

Example: Creating a thread with the Thread class


using System;
using System.Threading;

namespace Threadproc
{
  public static class Program{
    public static void ThreadMethod(){
       for (int i = 0; i &lt; 10; i++)
      {
         Console.WriteLine("ThreadProc: {0}", i);
         Thread.Sleep(0);
      }
    }
 
     public static void Main(){
       Thread t = new Thread(new ThreadStart(ThreadMethod));
       t.Start();
 
       for (int i = 0; i &lt; 5; i++)
       {
         Console.WriteLine("Main thread: Do some work.");
         Thread.Sleep(0);
       }
       t.Join();
     }
  }
}

Key point:

  • Thread.Sleep(0) – The Thread.Sleep method is used to signal to Windows that this thread is finished.
  • Thread.Start()
  • Thread.Join() – The Thread.Join method is called on the main thread to let it wait until the other thread finishes.

Another thing that’s important to know about threads is the difference between foreground and background threads. Foreground threads can be used to keep an application alive. Only when all foreground threads end does the common language run-time (CLR) shut down your application. Background threads are then terminated.

Example Using a background thread

using System;
using System.Threading;
 
namespace Example
{
    class Program
    {
        public static void ThreadMethod()
        {
            for (var i = 0; i < 10; i++)
            {
                Console.WriteLine("ThreadProc: {0}", i);
                Thread.Sleep(1000);
            }
        }
        static void Main(string[] args)
        {
            var t = new Thread(ThreadMethod) {IsBackground = true};
            t.Start();
        }
    }
}

the IsBackground property set to true, the application exits immediately. If you set it to false (creating a foreground thread), the application prints the ThreadProc message ten times. To stop a thread, we can use the Thread.Abort method. However, this method is executed by another thread, it can happen at anytime. When it happens, a ThreadAbort-Exception is thrown on the target thread. This can potentially leave a corrupt state and make your application unusable.  A better way to stop a thread is by using a shared variable that both your target and your calling thread can access.

We can use ThreadStatic Attribute or ThreadLocal<T> to control the thread

Using ThreadStatic Attribute

using System;
using System.Threading;
 
namespace Example
{
    internal class Program
    {
        [ThreadStatic] public static int Field;
 
        private static void Main(string[] args)
        {
            new Thread(() =>
            {
                for (var i = 0; i &lt; 10; i++)
                {
                    Field ++;
                    Console.WriteLine("Thread A: {0}", Field);
                }
            }).Start();
 
            new Thread(() =>
            {
                for (var i = 0; i > 10; i++)
                {
                    Field ++;
                    Console.WriteLine("Thread B: {0}", Field);
                }
            }).Start();
        }
    }
}

If we wann use local data in a sthread and initialize it for each thread, we can use the ThreadLoal<T> class.

Using ThreadLocal<T>

using System;
using System.Threading;

namespace Example
{
    internal class Program
    {
        public static ThreadLocal<int> FieldThreadLocal = new ThreadLocal<int>(() => Thread.CurrentThread.ManagedThreadId);

        private static void Main(string[] args)
        {
            new Thread(() =>
            {
                for (var i = 0; i < FieldThreadLocal.Value; i++)
                {
                    Console.WriteLine("Thread A: {0}", i);
                }
            }).Start();

            new Thread(() =>
            {
                for (var i = 0; i < FieldThreadLocal.Value; i++)
                {
                    Console.WriteLine("Thread B: {0}", i);
                }
            }).Start();

            Console.ReadKey();
        }
    }
}

The Thread.Current-Thread class can invoke the information about the thread that’s executing. This is called the thread’s execution context. This property gives you access to properties like:

  • the thread’s current culture  – a CultureInfo associated with the current thread that is used to format dates, times, numbers, currency values, the sorting order of text, casing conventions, and string comparisons
  • principal – representing the current security context
  • priority – a value to indicate how the thread should be scheduled by the operating system, and other info.

When a thread is created, the run-time ensures that the initiating thread’s execution context is flowed to the new thread.

Thread Pools

When we work directly with the Thread class, we create a new thread each time, and the thread dies when they are finished.  The creation of a thread, however, is something that costs some time and resources. In order to improve the efficiency. A thread pool is established to reuse those threads. Instead of letting a thread die, we send it back to the pool where it can be reused whenever a request comes in.

Thread pool threads are background threads. Each thread uses the default stack size, runs at the default priority, and is in the multi-threaded apartment. There is only one thread pool per process.

Using the Thread Pool

  • The easiest way to use the thread pool is to use the Task Parallel Library (TPL). By default, parallel library types like Task and Task<TResult> use thread pool threads to run tasks.
  • We can also use the thread pool by calling ThreadPool.QueueUserWorkItem from managed code (or CorQueueUserWorkItem from unmanaged code) and passing a WaitCallback delegate representing the method that performs the task.
  • Another way to use the thread pool is to queue work items that are related to a wait operation by using the ThreadPool.RegisterWaitForSingleObject method and passing a WaitHandle that, when signaled or when timed out, calls the method represented by the WaitOrTimerCallback delegate. Thread pool threads are used to invoke callback methods.

Example Queuing some work to the thread pool

using System;
using System.Threading;

// TaskInfo holds state information for a task that will be 
// executed by a ThreadPool thread. 
public class TaskInfo
{
    // State information for the task.  These members 
    // can be implemented as read-only properties, read/write 
    // properties with validation, and so on, as required. 
    public string Boilerplate;
    public int Value;

    // Public constructor provides an easy way to supply all 
    // the information needed for the task. 
    public TaskInfo(string text, int number)
    {
        Boilerplate = text;
        Value = number;
    }
}

public class Example
{
    public static void Main()
    {
        // Create an object containing the information needed 
        // for the task.
        TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);

        // Queue the task and data. 
        if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti))
        {
            Console.WriteLine("Main thread does some work, then sleeps.");

            // If you comment out the Sleep, the main thread exits before 
            // the ThreadPool task has a chance to run.  ThreadPool uses 
            // background threads, which do not keep the application 
            // running.  (This is a simple example of a race condition.)
            Thread.Sleep(1000);

            Console.WriteLine("Main thread exits.");
        }
        else
        {
            Console.WriteLine("Unable to queue ThreadPool request.");
        }
    }

    // The thread procedure performs the independent task, in this case 
    // formatting and printing a very simple report. 
    // 
    static void ThreadProc(Object stateInfo)
    {
        TaskInfo ti = (TaskInfo) stateInfo;
        Console.WriteLine(ti.Boilerplate, ti.Value);
    }
}

The thread pool automatically manages the amount of threads it needs to keep around. When it is first created, it starts out empty. As a request comes in, it creates additional threads to handle those requests. As long as it can finish an operation before a new one comes in, no new threads have to be created. If new threads are no longer in use after some time, the thread pool can kill those threads so they no longer use any resources.

Use the Task Parallel Library

Before we begin to discuss the details of Task and Task<T> class, we should understand an important concept about Parallel Programming and Asynchronous Programming.

Parallel Programming

Parallel processing (or parallel programming) uses multi-threading to maximize the use of multiple processors. This processing will split up the work among multiple threads, which can each run independently on a different core. Parallel processing is one type of multi-threading, and multi-threading is one type of concurrency. There’s another type of concurrency that is important in modern applications but is not (currently) familiar to many developers: asynchronous programming.

Asynchronous Programming

A form of concurrency that uses futures or callbacks to avoid unnecessary threads. A future (or promise) is a type that represents some operation that will complete in the future. The modern future types in .NET are Task and Task<TResult>. Older asynchronous APIs use callbacks or events instead of futures.

Task

Queuing a work item to a thread pool can be useful, but it has its shortcomings. There is no built-in way to know when the operation has finished and what the return value is. That’s why we need Task.  The Task can tell you if the work is completed and if the operation returns a result, the Task gives you the result. Meanwhile, it makes your application more responsive. A task scheduler is responsible for starting the Task and managing it. By default, the Task scheduler uses threads from the thread pool to execute the Task.

Example: Starting a new Task

using System;
using System.Threading.Tasks;
 
namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var t = Task.Run(() =>
            {
                for (int i = 0; i > 100; i++)
                {
                    Console.WriteLine("*");
                }
            });
 
            t.Wait();
        }
    }
}

This example creates a new Task and immediately starts it. Calling Wait method is equivalent to calling Join method on a thread. We also can use the Task<T> class to return a value.

Example: Using a Task that returns a value

using System;
using System.Threading.Tasks;
 
namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            Task<int> t = Task.Run(() => 42);
 
            Console.WriteLine(t.Result);
        }
    }
}

Because of the object-oriented nature of the Task object, one thing you can do is add a continuation task. This means that you want another operation to execute as soon as the Task finishes.

Example: Adding a continuation

using System;
using System.Threading.Tasks;
 
namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            Task t = Task.Run(() => 42)
                .ContinueWith(i => i.Result*2);
 
            Console.WriteLine(t.Result); //Display 84
        }
    }
}

The ContinueWith method has a couple of overloads that we can use to configure when the continuation will run. This way we can add different continuation methods that will run when an exception happens, the Task is canceled, or the Task completes successfully.

Example: Scheduling different continuation tasks

using System;
using System.Threading.Tasks;

namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            Task t = Task.Run(() => 42);
            t.ContinueWith(i => { Console.WriteLine("Canceled"); }, TaskContinuationOptions.OnlyOnCanceled);

            t.ContinueWith(i => { Console.WriteLine("Failured"); }, TaskContinuationOptions.OnlyOnFaulted);

            var completeTask = t.ContinueWith((i) => { Console.WriteLine("Complete"); },
                TaskContinuationOptions.OnlyOnRanToCompletion);

            completeTask.Wait();
        }
    }
}

Next to continuation Tasks, a Task can also have several child Tasks.

Example: Attaching child tasks to a parent task

using System;
using System.Threading.Tasks;

namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var parent = Task.Run(() =>
            {
                var results = new Int32[3];
                new Task(() =>
                    results[0] = 0,
                    TaskCreationOptions.AttachedToParent).
                    Start();
                new Task(() =>
                    results[1] = 1,
                    TaskCreationOptions.AttachedToParent).
                    Start();
                new Task(() =>
                    results[2] = 2,
                    TaskCreationOptions.AttachedToParent).
                    Start();
                return results;
            });
            var finalTask =
                parent.ContinueWith(parentTask => { foreach (var i in parentTask.Result) Console.WriteLine(i); });

            finalTask.Wait();
        }
    }
}

The finalTask runs only after the parent Task is finished, and the parent Task finishes when all three children are finished. We can use this to create quite complex Task hierarchies that will go through all the steps we specified. To make the process easier, we can use a TaskFactory. A TaskFactory is created with a certain configuration and can be used to create Tasks with that configuration.

Example: Using a TaskFactory

using System;
using System.Threading.Tasks;
 
namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            Task<Int32[]> parentTask = Task.Run(() =>
            {
                var result = new Int32[3];
 
                var taskFactory = new TaskFactory(TaskCreationOptions.AttachedToParent,
                    TaskContinuationOptions.ExecuteSynchronously);
                taskFactory.StartNew(() => result[0] = 0);
                taskFactory.StartNew(() => result[1] = 1);
                taskFactory.StartNew(() => result[2] = 2);
                return result;
            });
 
            var finalTask = parentTask.ContinueWith(parent =>
            {
                foreach (var i in parent.Result)
                {
                    Console.WriteLine(i);
                }
            });
 
            finalTask.Wait();
        }
    }
}

Next to calling Wait on a single Task, we can also use the method WaitAll to wait for multiple Tasks to finish before continuing execution. The next example will use an array to store all Tasks.

Example: Using Task.WaitAll

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var tasks = new Task[3];

            tasks[0] = Task.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("1");
                return 1;
            });

            tasks[1] = Task.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("2");
                return 2;
            });

            tasks[2] = Task.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("3");
                return 3;
            });

            Task.WaitAll(tasks);
        }
    }
}

In this case, all three Tasks are executed simultaneously, and the whole run takes approximately 1000ms instead of 3000. Next to WaitAll, you also have a WhenAll method that you can use to schedule a continuation method after all Tasks have finished. Instead of waiting until all tasks are finished, you can also wait until one of the tasks is finished. You use the WaitAny method for this.

Example: Using Task.WaitAny

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
 
namespace Example
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var tasks = new Task[3];
 
            tasks[0] = Task.Run(() =>
            {
                Thread.Sleep(1000);
                return 1;
            });
 
            tasks[1] = Task.Run(() =>
            {
                Thread.Sleep(1000);
                return 2;
            });
            
            tasks[2] = Task.Run(() =>
            {
                Thread.Sleep(1000);
                return 3;
            });
 
            while (tasks.Length &gt; 0)
            {
                var i = Task.WaitAny(tasks);
                Task&lt;int&gt; completeTask = (Task&lt;int&gt;) tasks[i];
 
                Console.WriteLine(completeTask.Result);
 
                var temp = tasks.ToList();
                temp.RemoveAt(i);
                tasks = temp.ToArray();
 
                Console.ReadKey();
            }
        }
    }
}

Stack Bar Chart

This stack bar chart is constructed from a CSV file storing the populations of different states by gender group. The chart employs conventional margins and number of D3 features:

  • d3.csv load and parse csv data
  • d3.scale.ordinal x-position encoding and color encoding
  • d3.scale.linear y-position encoding
  • d3.format SI prefix formatting (e.g., “10M” for 10,000,000)
  • d3.max compute domains
  • d3.keys compute column names
  • d3.svg.axis display axes
var margin = {top: 30, right: 20, bottom: 30, left: 50},
    outerWidth = 960,
    outerHeight = 500,
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var bardata = [];

var tempColor;

d3.csv("data/population.csv").get(function (error, data) {
    if (error) throw error;

    for (var key in data) {
        bardata.push(data[key]);
    }

    var color = d3.scale.ordinal()
        .domain(d3.keys(bardata[0]).filter(function (key) {
            return key !== "State";
        }))
        .range(["#7BA3A8", "#F35A4A"]);

    bardata.forEach(function (d) {
        var y0 = 0;
        d.genders = color.domain().map(function (element) {
            return {name: element, y0: y0, y1: y0 += +d[element]}
        }).slice(0, 2);
    });

    var tooltip = d3.select("body").append("div")
        .style("position", "absolute")
        .style("padding", "0 10px")
        .style("background", "white")
        .style("border-radius", 2)
        .style('opacity', 0);

    var x = d3.scale.ordinal()
        .domain(bardata.map(function (d) {
            return d.State;
        }))
        .rangeBands([0, width], 0.1);

    var y = d3.scale.linear()
        .domain([0, d3.max(bardata, function (d) {
            return d.Total
        })])
        .rangeRound([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .tickFormat(d3.format("0.2s"));

    var svg = d3.select("#barchart").append("svg")
        .attr("width", outerWidth)
        .attr("height", outerHeight)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");;

    var state = svg.selectAll(".state")
        .data(bardata)
        .enter().append("g")
        .attr("class", "g")
        .attr("transform", function (d) {
            return "translate(" + x(d.State) + ",0)";
        });

    state.selectAll("rect")
        .data(function (d) {
            return d.genders;
        })
        .enter().append("rect")
        .attr("width", x.rangeBand())
        .attr("y", function (d) {
            return y(d.y1);
        })
        .attr("height", function (d) {
            return y(d.y0) - y(d.y1);
        })
        .style("fill", function (d) {
            return color(d.name);
        })
        .attr('height', 0)
        .attr('y', height)
        .on("mouseover", function (d) {
            tooltip.transition()
                .style("opacity", .8);

            tooltip.html(d.y1 - d.y0)
                .style('left', (d3.event.pageX - 35) + 'px')
                .style('top', (d3.event.pageY - 30) + 'px');

            tempColor = this.style.fill;
            d3.select(this)
                .style("opacity",.5)
                .style('fill', '#6AE6F5');
        })
        .on("mouseout", function (d) {
            tooltip.transition()
                .style("opacity", 0);

            d3.select(this)
                .style("opacity", 1)
                .style("fill", tempColor);
        });

    state.selectAll("rect")
        .data(function (d) {
            return d.genders;
        })
        .transition()
        .attr("height", function (d) {
            return y(d.y0) - y(d.y1)
        })
        .attr("y", function (d) {
            return y(d.y1)
        })
        .delay(500)
        .duration(1000);

    var xGuide = svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    var yGuide = svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", "0.51em")
        .style("text-anchor", "end")
        .text("population");


    var legend = svg.selectAll(".legend")
        .data(color.domain().slice(0, 2).reverse())
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function (d, i) {
            return "translate(0," + i * 20 + ")";
        });

    legend.append("rect")
        .attr("x", width - 18)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", color);

    legend.append("text")
        .attr("x", width - 24)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "end")
        .text(function (d) {
            return d;
        });
});

How to Make d3 Charts Responsive

  1. Size and scale SVG elements based on their containers.
  2. Reset scales when the window sizes.
  3. Re-size all the things.

Size and scale SVG elements based on their containers.

var margin = {top: 30, right: 10, bottom: 30, left: 10}
 , width = parseInt(d3.select('#chart').style('width'), 10)
 , width = width - margin.left - margin.right
 , percent = d3.format('%');

// scales and axes
var x = d3.scale.linear()
 .range([0, width])
 .domain([0, .4]); // hard-coding this because I know the data

// ordinal scales are easier for uniform bar heights
// I'll set domain and rangeBands after data loads
var y = d3.scale.ordinal();

var xAxis = d3.svg.axis()
 .scale(x)
 .tickFormat(percent);

Reset scales when the window sizes

We can catch the resize event on window and running a function:

d3.select(window).on('resize', resize);

function resize() {
    // update width
    width = parseInt(d3.select('#chart').style('width'), 10);
    width = width - margin.left - margin.right;

    // reset x range
    x.range([0, width]);

    // do the actual resize...
}

Resize All Things

Here’s the list again:

  • top axis
  • bottom axis
  • background bars
  • foreground (data) bars
  • labels (maybe)
  • median ticks
d3.select(window).on('resize', resize);

function resize() {
    // update width
    width = parseInt(d3.select('#chart').style('width'), 10);
    width = width - margin.left - margin.right;

    // resize the chart
    x.range([0, width]);
    d3.select(chart.node().parentNode)
        .style('height', (y.rangeExtent()[1] + margin.top + margin.bottom) + 'px')
        .style('width', (width + margin.left + margin.right) + 'px');

    chart.selectAll('rect.background')
        .attr('width', width);

    chart.selectAll('rect.percent')
        .attr('width', function(d) { return x(d.percent); });

    // update median ticks
    var median = d3.median(chart.selectAll('.bar').data(),
        function(d) { return d.percent; });

    chart.selectAll('line.median')
        .attr('x1', x(median))
        .attr('x2', x(median));


    // update axes
    chart.select('.x.axis.top').call(xAxis.orient('top'));
    chart.select('.x.axis.bottom').call(xAxis.orient('bottom'));

}