ASP.NET Core with PostgreSQL and Entity Framework Core

This article shows how to use PostgreSQL with ASP.NET Core 3.1 using Entity Framework Core.

Code: https://github.com/damienbod/AspNetCoreMultipleProject

Posts in this series:

2020-01-10: Updated to ASP.NET Core 3.1
2018-12-05: Updated to ASP.NET Core 2.2 and EF Core 2.2
2017-08-16: Updated to ASP.NET Core 2.1 and EF Core 2.1
2017-08-17: Updated to ASP.NET Core 2.0 and EF Core 2.0
2017-02-10: Updated to VS2017 and msbuild
2016-12-01: Updated to ASP.NET Core 1.1
2016-07-02: Updated to ASP.NET Core RTM
2016-05-17: Updated to ASP.NET Core RC2 dotnet

The PostgreSQL Entity Framework Core provider can be downloaded as a NuGet package. Add the NuGet package Npgsql.EntityFrameworkCore.PostgreSQL to your dependencies in the csproj file file.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AssemblyName>DataAccessPostgreSqlProvider</AssemblyName>
    <PackageId>DataAccessPostgreSqlProvider</PackageId>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\DomainModel\DomainModel.csproj" />
  </ItemGroup>
  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0" PrivateAssets="All" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="Properties\" />
  </ItemGroup> 
</Project>

The web project which loads the project with EF Core needs to support migrations if you wish to create a database this way.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AssemblyName>AspNetCoreMultipleProject</AssemblyName>
    <PackageId>AspNet5MultipleProject</PackageId>
    <StartupObject>AspNetCoreMultipleProject.Program</StartupObject>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\DataAccessMsSqlServerProvider\DataAccessMsSqlServerProvider.csproj" />
    <ProjectReference Include="..\DataAccessMySqlProvider\DataAccessMySqlProvider.csproj" />
    <ProjectReference Include="..\DataAccessPostgreSqlProvider\DataAccessPostgreSqlProvider.csproj" />
    <ProjectReference Include="..\DataAccessSqliteProvider\DataAccessSqliteProvider.csproj" />
    <ProjectReference Include="..\DomainModel\DomainModel.csproj" />
  </ItemGroup>
  
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0" PrivateAssets="All" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc5" />
  </ItemGroup>
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
  </ItemGroup>
</Project>

Create the context for Entity Framework Core which is used for the PostgreSQL database.

using System;
using System.Linq;
using DomainModel.Model;
using Microsoft.EntityFrameworkCore;

namespace DataAccessPostgreSqlProvider
{
    // >dotnet ef migration add testMigration in AspNet5MultipleProject
    public class DomainModelPostgreSqlContext : DbContext
    {
        public DomainModelPostgreSqlContext(DbContextOptions<DomainModelPostgreSqlContext> options) :base(options)
        {
        }
        
        public DbSet<DataEventRecord> DataEventRecords { get; set; }

        public DbSet<SourceInfo> SourceInfos { get; set; }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<DataEventRecord>().HasKey(m => m.DataEventRecordId);
            builder.Entity<SourceInfo>().HasKey(m => m.SourceInfoId);

            // shadow properties
            builder.Entity<DataEventRecord>().Property<DateTime>("UpdatedTimestamp");
            builder.Entity<SourceInfo>().Property<DateTime>("UpdatedTimestamp");

            base.OnModelCreating(builder);
        }

        public override int SaveChanges()
        {
            ChangeTracker.DetectChanges();

            updateUpdatedProperty<SourceInfo>();
            updateUpdatedProperty<DataEventRecord>();

            return base.SaveChanges();
        }

        private void updateUpdatedProperty<T>() where T : class
        {
            var modifiedSourceInfo =
                ChangeTracker.Entries<T>()
                    .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);

            foreach (var entry in modifiedSourceInfo)
            {
                entry.Property("UpdatedTimestamp").CurrentValue = DateTime.UtcNow;
            }
        }
    }
}

Add the POCO classes to use as entities.

public class DataEventRecord
{
	[Key]
	public long DataEventRecordId { get; set; }
	public string Name { get; set; }
	public string Description { get; set; }
	public DateTime Timestamp { get; set; }
	[ForeignKey("SourceInfoId")]
	public SourceInfo SourceInfo { get; set; }
	public long SourceInfoId { get; set; }
}
}

public class SourceInfo
{
	[Key]
	public long SourceInfoId { get; set; }
	public string Name { get; set; }
	public string Description { get; set; }
	public DateTime Timestamp { get; set; }
	public List<DataEventRecord> DataEventRecords { get; set; }
}

The connection string can be added in the OnConfiguring method in the class which implements the DbContext, or via dependency injection in the constructor using the options. The connection string property User ID needs to exist in the database and should have the create database rights.

{
    "ConnectionStrings": {     
        "DataAccessPostgreSqlProvider":  "User ID=damienbod;Password=1234;Host=localhost;Port=5432;Database=damienbod;Pooling=true;"
        }
    }
}

Open pgAdmin to configure the user in PostgreSQL.

EF7_PostgreSQL_01

Right click your user and click propeties to set the password

EF7_PostgreSQL_02

Set up the migration scripts now. Open the command line in the same folder where the context is added in the Startup.

>
> dotnet restore
>
> dotnet ef migrations add postgresqlMigration --context DomainModelPostgreSqlContext
> 
> dotnet ef database update --context DomainModelPostgreSqlContext
>

The database should now exist. Add Entity Framework Core to the ASP.NET Core application in the Startup class. A DataAccessPostgreSqlProvider class with an interface is used to access the context from anywhere else in the application.

public void ConfigureServices(IServiceCollection services)
{
	// Use a PostgreSQL database
	var sqlConnectionString = Configuration.GetConnectionString("DataAccessPostgreSqlProvider");

	services.AddDbContext<DomainModelPostgreSqlContext>(options =>
		options.UseNpgsql(
			sqlConnectionString,
			b => b.MigrationsAssembly("AspNet5MultipleProject")
		)
	);

	services.AddScoped<IDataAccessProvider, DataAccessPostgreSqlProvider.DataAccessPostgreSqlProvider>();

	JsonOutputFormatter jsonOutputFormatter = new JsonOutputFormatter
	{
		SerializerSettings = new JsonSerializerSettings
		{
			ReferenceLoopHandling = ReferenceLoopHandling.Ignore
		}
	};

	services.AddMvc(
		options =>
		{
			options.OutputFormatters.Clear();
			options.OutputFormatters.Insert(0, jsonOutputFormatter);
		}
	);
}

Now the PostgreSQL provider can be used in a MVC controller using construction injection.

using System.Collections.Generic;
using DomainModel;
using DomainModel.Model;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace AspNet5MultipleProject.Controllers
{
    [Route("api/[controller]")]
    public class DataEventRecordsController : Controller
    {
        private readonly IDataAccessProvider _dataAccessProvider;

        public DataEventRecordsController(IDataAccessProvider dataAccessProvider)
        {
            _dataAccessProvider = dataAccessProvider;
        }

        [HttpGet]
        public IEnumerable<DataEventRecord> Get()
        {
            return _dataAccessProvider.GetDataEventRecords();
        }

        [HttpGet]
        [Route("SourceInfos")]
        public IEnumerable<SourceInfo> GetSourceInfos(bool withChildren)
        {
            return _dataAccessProvider.GetSourceInfos(withChildren);
        }

        [HttpGet("{id}")]
        public DataEventRecord Get(long id)
        {
            return _dataAccessProvider.GetDataEventRecord(id);
        }

        [HttpPost]
        public void Post([FromBody]DataEventRecord value)
        {
            _dataAccessProvider.AddDataEventRecord(value);
        }

        [HttpPut("{id}")]
        public void Put(long id, [FromBody]DataEventRecord value)
        {
            _dataAccessProvider.UpdateDataEventRecord(id, value);
        }

        [HttpDelete("{id}")]
        public void Delete(long id)
        {
            _dataAccessProvider.DeleteDataEventRecord(id);
        }
    }
}

The controller api can be called using Fiddler:

POST http://localhost:5000/api/dataeventrecords HTTP/1.1
User-Agent: Fiddler
Host: localhost:5000
Content-Length: 135
Content-Type: application/json;
 
{
  "DataEventRecordId":3,
  "Name":"Funny data",
  "Description":"yes",
  "Timestamp":"2015-12-27T08:31:35Z",
   "SourceInfo":
  { 
    "SourceInfoId":0,
    "Name":"Beauty",
    "Description":"second Source",
    "Timestamp":"2015-12-23T08:31:35+01:00",
    "DataEventRecords":[]
  },
 "SourceInfoId":0 
}

The data can be viewed now in PostgreSQL.

EF7_PostgreSQL_03

PostgreSQL is a great choice for a rational database if you what to support multiple runtime environments.

Links:

https://docs.microsoft.com/en-us/ef/core/

http://www.postgresql.org

http://www.pgadmin.org/

https://github.com/npgsql/npgsql

http://www.npgsql.org/doc/ef7.html

Experiments with Entity Framework Core and an ASP.NET Core API

39 comments

  1. Hi,
    Your job seems very cool but I got an error running “dnu restore” on searching for DomainModel package. What is this package!? How can I reference it?

    Thank you

    1. Hi

      The DomainModel package is the project in the src. This should build per default. It is referenced in the project.json file.

      Does the DomainModel package build. What happens in the dnu restore in the cmd line? rc1 is required.

      Hope this helps

      Greetings Damien

      1. Hi Bobbe Maresca

        Thanks for your feedback. This was a problem, I did a fix and pushed it, it should work now. I had an incorrect project name.

        Greetings Damien

  2. sumatan · · Reply

    migration doesn’t work. It only creates the migration table. I’m I doing something wrong?

    1. Hi sumatan

      It should work, have you setup the database and it’s running?, ASP.NET Core RC1? The committed migrations for the Postgres are for ‘damienbod’. If you setup a different db, you need to delete these and recreate the migrations.

      greetings Damien

  3. Nice post. However, I am getting stuck on the migration step. It only creates the _EFMMigrationsHistory table. I’m I missing something here. I’m using github source. 🙂

    1. I’m hitting, {“42P01: relation \”DataEventRecord\” does not exist”}

  4. Hi!
    I have a problem… When I run dotnet ef migrations add testPG return the message “More than one DbContext was found. Specify which one to use. Use the ‘-Context’ parameter for PowerShell commands and the ‘–context’ parameter for dotnet commands”.
    I follow all the steps with the options configurated of the demo.

    1. Hi, thanks, you need to define the context as well in the command dotnet ef migrations dddd –context YourContext

      Greetings Damien

  5. Hi, I am kind of a noob. If I use Visual Studio to generate a project using ASp.NET Core MVC, would I be able to switch the database to PostgreSQL using this tutorial?

    1. Hi Vlad

      Yes, EFCore is used as the ORM

      greetings Damien

  6. Thanks! I’ve managed to make an ASP.NET Core MVC project generator for yeoman with PostgreSQL support, you can find it here if you are interested: https://github.com/DeathArrow01/generator-aspnetpostgresql

    It’s a quick hack of another project generator buy it works.

    1. Hi Vlad

      cool, thanks for the link

      Greetings Damien

  7. […] ASP.NET Core 1.0 with PostgreSQL and Entity Framework Core | Software Engineering – […]

  8. Thank you Damienbod for this post, it’s very useful!

    Only one question, I’m getting this error messsage: An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point.

    This happens when I try to do 2 request in a row and both connect to the database to get some rows. I’m getting this error running locally, I imagine when I’ll have concurrency this could be worst.

    Do you know a fix for this?

    Thank in advance.

    1. Hi Mateus

      I don’t fully get what your setup is, could you maybe post some code, maybe a gitHub issue and I’ll have a look. Each HTTP request should have its own context, or if 2 requests to the database are sent for a single HTTP request, the same context should be used.

      Greetings Damien

  9. mziyabo · · Reply

    Hey man. Thanks for updating to the .csproj file. Is there anything else you did to get it working after dotnet migrate? I must’ve broken something after the migration. Getting No executable found matching dotnet-ef

    1. Thanks, no should work, I just did a dotnet restore. I will check it for PostgreSQL

  10. Hi, thx for this post, I am a noob in VS and MVC, but i need it(( so can you share your example. Because i don’t understand where i should put “Create the context for Entity Framework Core which is used for the PostgreSQL database.” code and etc. Please)))

      1. sorry for my another stupid question, but how can i check for a connection and get data, where should i write sql code? I changed startup.cs for postgre connection. Also i changed connection string in config.json. And what next? when i run the app i see “Server running” and that’s all cause it’s in index page. Sorry once again

      2. in the Context class see the EF Core docs from Microsoft these are really good

  11. Rafael Brugnollo · · Reply

    Getting this error when trying to generate the migrations. Any ideas?

    dotnet : No executable found matching command “dotnet-ef”
    At line:1 char:1
    + dotnet ef migration add testMigration
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (No executable f…and “dotnet-ef”:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

  12. Hello There. Do you have a working example to share ? Thanks!

  13. […] If you want a quick setup guide from someone that probably knows what he’s doing. check this link. […]

  14. “Hi!
    I have a problem… When I run dotnet ef migrations add testPG return the message “More than one DbContext was found. Specify which one to use. Use the ‘-Context’ parameter for PowerShell commands and the ‘–context’ parameter for dotnet commands”.
    I follow all the steps with the options configurated of the demo.”

    Correct answer is:

    1) simply delete content under src\Migrations tab, which included into source tree (MySQL EF adapter)

    2) comment and select correct lines in main flie Startup.css which corresponds to the database of your chose

    3) restart commands:

    dotnet ef migrations add testPG
    dotnet ef database update

    4) continue

  15. You missed a line 63 (which includes a SourceInfo to the result set):

    public List GetDataEventRecords()
    {
    // Using the shadow property EF.Property(dataEventRecord)
    //_context.SourceInfos.Include(s => s.DataEventRecords).OrderByDescending(srcInfo => EF.Property(srcInfo, “UpdatedTimestamp”)).ToList();
    _context.DataEventRecords.Include(s => s.SourceInfo).OrderByDescending(dataEventRecord => EF.Property(dataEventRecord, “UpdatedTimestamp”)).ToList();
    return _context.DataEventRecords.OrderByDescending(dataEventRecord => EF.Property(dataEventRecord, “UpdatedTimestamp”)).ToList();
    }

    Result will be like:

    [
    {
    “dataEventRecordId”: 1,
    “name”: “text”,
    “description”: “description “,
    “timestamp”: “2015-12-27T08:31:35”,
    “sourceInfo”: {
    “sourceInfoId”: 1,
    “name”: “source info name”,
    “description”: “source info test”,
    “timestamp”: “2015-12-27T08:31:35”,
    “dataEventRecords”: []
    },
    “sourceInfoId”: 1
    }
    ]

    Otherwize:

    [
    {
    “dataEventRecordId”: 1,
    “name”: “text”,
    “description”: “description “,
    “timestamp”: “2015-12-27T08:31:35”,
    “sourceInfo”: null,
    “sourceInfoId”: 1
    }
    ]

  16. Great Article! Thanks for sharing your knowledge. I’ve a question. What’s the best way to use EF Core in a psql db replication? Can you show a full example of how to do get queries using a readonly context and inserts/updates using a read-write context? I’m not able to understand when to select the connection string and how to assign it to the context at runtime for an api project

    1. Yes, i understand you question. In my opinion, the best way is to use a EF – avoid using it for replication, because usually the most efficient way to replicate databases is native replication, without materialization – dematerialization (or serialization – deserialization DTO objects within in-memory replication process), so EF is of no use at all in this scenario, or at least you can share generated by EF Core classes (due to the usage of database-first scenario, where DB classes are generated by dotnet core commands). The most simple scenario as I see it is to use DB-first approach on one side for replication, wilst use a code-first approach on the other end of replication sequence, so if you match this to approaches with generated EF database Context classes and sequences in one project, theoretically by using DTO objects and passing them by any means from one context to another context, connected to other db instance, you will be able to replicate db structure of the source database as well as some data you will provide for it, but in most cases this approach will not work. There are some reasons that EF replication will fail – one is a coherence, and other is integrity. Also, there are always be a scenarios where there are more than one working thread are needed or DB connections used to complete some tasks, so it can all ruin in any time. It will definetely work if your database is small and you are going to use a full replication strategy, limit access to database by one instance, try use one writer-multiple reader or use other syncronization mechanizms to deliver a corerent and sync-ed database witout some of the errors. Of cause you can programmatically fill all the cases, and of cause provide some write blocking mechanizm for a time of synchronization or implement some non-blocking approach which can garantee that replication will not end prematurely or end up with unexpected error and will always finish replication if at some point of time you leave a source database “intact” (i mean without any queued writes), for a time frame big enouth so you can finish non-blocking replication at this time

  17. Hi! Thanks for your blog and it is amazingly helpful. One more question, do you have any resources or docs about how to set up Postgres in this case on Linux with shell portal instead of GUI?
    Thanks?

  18. asdfa@asdf.net · · Reply

    Unable to create an object of type ‘DomainModelPostgreSqlContext’. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

    1. should work now

      Greetings Damien

  19. Keshav Tiwari · · Reply

    Unable to call PostgreySQl stored procedure from DataAccessLayer class..
    And run insert and select query simultaneously in Stored Procedure. Please help.

    1. Hi Keshav

      I’ll have a look but maybe you have already solved this

      Greetings Damien

  20. Kimball Johnson · · Reply

    If you are going to produce more articles on this topic, please identify OS in Title.
    The most important aspect of .NET core is it’s cross-platform capability.
    If you ignore that by using ASP.NET core on Windows, I would ask: what’s the point?

  21. […] Currently I am doing database migration using MVC6 on .netcore 2.0. here is the link that I am following, to migrate POSTGRESQL : https://damienbod.com/2016/01/11/asp-net-5-with-postgresql-and-entity-framework-7/ […]

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.