1

I keep getting the following error when trying to initialize my SQLite-NET database:

Cannot create a table without columns (does 'PersonModel' have public properties?)

I have a class PersonModel that I want to be immutable, however SQLite is telling me that PersonModel must be mutable, e.g. each property must use public set;.

How can I continue using SQLite-NET with immutable properties?

class Person
{
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public string FirstName { get; } //Read-only Property, cannot be changed after initialization
    public string LastName { get; } //Read-only Property, cannot be changed after initialization
}
Brandon Minnick
  • 13,342
  • 15
  • 65
  • 123

2 Answers2

3

Explanation

That error is happening because SQLite-NET uses Reflection to initialize the objects it retrieves from our database, and Reflection requires public set; to initialize each property.

Answer

We can take advantage of Init-Only Setters, new in C# 9.0.

Init-Only Setters allow us to define properties that can be set during initialization, AND cannot be changed. In other words init-only setters let us create immutable objects, AND they allow Reflection to create Immutable Objects!

I go deeper into this topic in this blog post: https://codetraveler.io/2020/11/11/using-immutable-objects-with-sqlite-net/

Code

Remove the constructor on Person (Reflection requires a parameterless constructor), and implement init-only setters for each property:

class Person
{
    public string FirstName { get; init; } //Read-only Property, can be set during initialization, but cannot be changed after initialization
    public string LastName { get; init; } //Read-only Property, can be set during initialization, but cannot be changed after initialization
}
Brandon Minnick
  • 13,342
  • 15
  • 65
  • 123
0

Another option is to create a PersonDto class that does all of the SQLite interactions:

class PersonDto
{
    
    public PersonDto(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Then the Person class encapsulates the DTO object:

class Person
{
    private PersonDto _dto;
    
    public Person(PersonDto dto)
    {
        this._dto = dto;
    }

    public string FirstName => _dto.FirstName;
    public string LastName => _dto.LastName;
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172