如何在 SQLite 中使用不可变对象?

How to use Immutable Objects with SQLite?

我在尝试初始化我的 SQLite-NET 数据库时不断收到以下错误:

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

我有一个 class PersonModel 我想保持不变,但是 SQLite 告诉我 PersonModel 必须是可变的,例如每个 属性 必须使用 public set;.

我如何才能继续使用具有不可变属性的 SQLite-NET

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
}

说明

发生该错误是因为 SQLite-NET 使用 Reflection 来初始化它从我们的数据库中检索到的对象,而反射需要 public set; 来初始化每个 属性.

回答

我们可以利用Init-Only Setters, new in C# 9.0

Init-Only Setters 允许我们定义可以在初始化期间设置并且不能更改的属性。换句话说,init-only setter 让我们创建不可变对象,并且它们允许反射创建不可变对象!

我在这篇博客中更深入地探讨了这个话题 post:https://codetraveler.io/2020/11/11/using-immutable-objects-with-sqlite-net/

代码

删除 Person 上的构造函数(反射需要无参数构造函数),并为每个 属性:

实现仅初始化设置器
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
}

另一种选择是创建一个 PersonDto class 来执行所有 SQLite 交互:

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

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

然后Personclass封装DTO对象:

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

    public string FirstName => _dto.FirstName;
    public string LastName => _dto.LastName;
}