Home > Blockchain >  Entity Framework: Unable to add a record
Entity Framework: Unable to add a record

Time:04-13

I am new to C# development and I am trying to write something that can insert a record in a DB. I have a simple test, which I hoped would insert a record into the database when I run it.

Model:

namespace Users.Models;

using System.ComponentModel.DataAnnotations.Schema;

public class User
{ 
    public int Id { get; set; }
    public string Name { get; set; }
    public string EmailAddress { get; set; }
    public string HashedPassword { get; set; }
    public DateTime Created { get; set; }
}

Test:

namespace Database.Tests;

using Users.Models;
using Xunit;

public class ReferrerTests
{
    [Fact]
    public void TestInsert()
    {
        User user = new()
        {
            Name = "Bob",
            EmailAddress = "[email protected]",
            HashedPassword = "hgfj",
        };

        using MyDbContext ctx = new();
        ctx.Users.Add(user);
    }
}

Database context:

namespace Database;

using Users.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using Npgsql;

[DbConfigurationType(typeof(Config))]
[SuppressDbSetInitialization]
public class MyDbContext: DbContext
{
    public MyDbContext(): base(MakeConnString()) {}

    private static string MakeConnString()
    {
        // Will be moving these to a common location
        string OptEnv(string key, string default_) =>
            Environment.GetEnvironmentVariable(key) ?? default_;

        string Env(string key) =>
            Environment.GetEnvironmentVariable(key) ?? throw new MissingFieldException(key);

        NpgsqlConnectionStringBuilder builder = new()
        {
            Host = Env("PGHOST"),
            Port = int.Parse(OptEnv("PGPORT", "5432")),
            SslMode = Enum.Parse<SslMode>(OptEnv("PGSSLMODE", "Require")),
            TrustServerCertificate = true,
            Database = OptEnv("PGDATABASE", "postgres"),
            Username = OptEnv("PGUSER", "postgres"),
            Password = Env("PGPASSWORD")
        };
        return builder.ConnectionString;
    }
    public DbSet<User> Users { get; set; }
}

When running this code I get:

System.NullReferenceException: Object reference not set to an instance of an object.

I think I must have something that is preventing the mapping to my database, but I have been unable to figure it out.

EDIT

I think it's probably important I show the DDL of the table as well:


create table public.user
(
    id            integer generated always as identity primary key,
    name          text                                               not null
        constraint user_name_check
            check (length(name) > 0),
    email_address text                                               not null unique
        constraint user_email_address_check
            check (email_address ~* '^. @. \.. $'),
    -- Ideally use something like 
    -- https://www.postgresql.org/docs/13/pgcrypto.html
    hash_password text                                               not null
        constraint user_password_hash_check
            check (length(password_hash) > 0),
    created       timestamp with time zone default CURRENT_TIMESTAMP not null
        constraint user_created_check
            check (created <= CURRENT_TIMESTAMP)
);

alter table public."user"
    owner to postgres;

EDIT 2:

Suggestions to use annotations to try to get the model to map directly to the DDL - still gives the same error, but this is our new model.

namespace Users.Models;

using System.ComponentModel.DataAnnotations.Schema;


[Table("user", Schema="public")]
public class User
{ 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Column("id")]
    public int Id { get; set; }
    
    [Column("name")]
    public string Name { get; set; }
    
    [Column("email_address")]
    public string EmailAddress { get; set; }
    
    [Column("hash_password")]
    public string HashedPassword { get; set; }
    
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    [Column("created")]
    public DateTime Created { get; set; }
}

CodePudding user response:

I don't know about your DB but your model requires the Id column to have a value (it's not nullable) So you need to proivde a value in order to do that.

If your Id column type is Serial on the DB side, just decorate your Id column with :

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }

CodePudding user response:

Following @DubDub advice, removing the following line fixed it:

[SuppressDbSetInitialization]
  • Related