Following lab setup, in this post, I will show how to use dotnet core to access Postgres db.

Summary

  • Create a dotnet core console project
  • use Entity Framework to generate Entity Framework context and entity code
  • write code to run a query using Entity Framework
  • write code to run a query using ADO.Net/Npgsql
  • run a speed test

Create a dotnet project and add Postgres packages

dotnet new console -n CmdlineApp
cd CmdlineApp
dotnet add package Npgsql --version 4.0.5
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 2.2.0

# set up connection string
$cnstr = "Host={0};Database={1};Username={2};Password={3}" -f $env:PGHOST,$env:PGDATABASE,$env:PGUSER,$env:PGPASSWORD
dotnet ef dbcontext scaffold $cnstr Npgsql.EntityFrameworkCore.PostgreSQL

# brunoContext.cs and College.cs generated

Write some code

Source code on my github repo

EF query

 int ret = 0;
brunoContext.ConnectionString = ConnectionString;
string sqltext = (!queryByName) ? "select * from yin.college where id = {0}"
    :"select * from yin.college where earnings is not null and name ~* {0} order by earnings desc limit 20";
using (var context = new brunoContext())
{
    Task<List<College>> task = context.College
        .FromSql(sqltext, val)
        .ToListAsync();
    Console.WriteLine("Waiting for query to finish ...");
    var college = await task;
    foreach(var item in college){
        Console.WriteLine(item.Info);
        Log.Information(item.Info);
    }
    ret = college.Count;
}
return ret;

ADO.Net query: a little bit more work

DBNull value needs to be handled, this can be achieved using the private method:

decimal? ToDecimal(Object v){
    return (v is System.DBNull)? null: (decimal?)v;
}

Each column value has to be handled manually:

using(var cn = new NpgsqlConnection(ConnectionString)){
string sqltext = (!queryByName) ? "select * from yin.college where id = @p1"
    :"select * from yin.college where earnings is not null and name ~* @p1 order by earnings desc limit 20";
await cn.OpenAsync();
var cmd = new NpgsqlCommand(sqltext, cn);
var p1 = cmd.Parameters.Add("p1", NpgsqlDbType.Varchar, 32);
p1.Value = val;
var r = await cmd.ExecuteReaderAsync();
int total = 0;
while(r.Read()){
    Object[] values = new Object[r.FieldCount];
    int fieldCount = r.GetValues(values);
    College item = new College{
        Id = (string)values[0], Name = (string)values[1],City = (string)values[2],State = (string)values[3],
        Zip = (string)values[4],Region = (int)values[5], 
        Latitude = ToDecimal(values[6]), Longitude = ToDecimal(values[7]),
        AdmRate = ToDecimal(values[8]), SatAvg = ToDecimal(values[9]), ActAvg=ToDecimal(values[10]),
        Earnings=ToDecimal(values[11]), Cost=ToDecimal(values[12]),Enrollments=ToDecimal(values[13])
    };
    Log.Information(item.Info);
    Console.WriteLine(item.Info);
    total ++;
}
ret = total;

run a speed test

Use a Powershell script

$testEF = {    
    dotnet run -n cali -qt ef
}

$testSimple = {
    dotnet run -n cali
}

Function runTest{
    Param(
        [scriptblock]$Script
    )
    $w = New-Object System.Diagnostics.Stopwatch
    $w.Start()
    & $Script | Out-Null
    $w.Stop()
    # "`n{0:#,###.#0} milli seconds used`n" -f $w.Elapsed.TotalMilliseconds
    $w.Elapsed.TotalMilliseconds
}
 
$results = @()

1 .. 25 | % {
    $a = runTest -Script $testEF
    $b = runTest -Script $testSimple

    $results += New-Object -TypeName psobject -Property @{EF=$a; Simple=$b; Difference=$b-$a }
}

$results

Test results

EF runs on top of Npgsql, it’s easy to predict that ADO/Npgsql runs faster than EF:

> Difference    Simple        EF
> ----------    ------        --
> -890.4726 2003.5534  2894.026
> -790.5495 2026.9623 2817.5118
> -803.0365 2023.1614 2826.1979
> -683.2189 2137.6329 2820.8518
> -787.4604 2067.4506  2854.911
> -873.2238 2066.3301 2939.5539
> -828.5192 2011.5325 2840.0517
> -788.0466 2070.0426 2858.0892
> -757.0905 2055.0067 2812.0972
> -745.6193   2085.95 2831.5693
> -812.5492 2031.2828  2843.832
> -778.6706  2036.892 2815.5626
> -779.2398 2032.2943 2811.5341
> -763.1625 2045.6339 2808.7964
> -911.0323 2029.7009 2940.7332
> -821.3651 1992.6945 2814.0596
> -802.1631 2011.2111 2813.3742
> -781.8481   2038.95 2820.7981
> -787.0569 2059.4261  2846.483
> -773.6388 2036.2037 2809.8425
> -794.3785 2027.4133 2821.7918
> -811.3318 2031.5567 2842.8885
> -811.1682 2000.7685 2811.9367
> -809.3262 2014.9895 2824.3157
> -763.4612  2029.836 2793.2972
>