简体   繁体   English

如何将不可变对象与 SQLite 一起使用?

[英]How to use Immutable Objects with SQLite?

I keep getting the following error when trying to initialize my SQLite.NET database:尝试初始化SQLite.NET数据库时,我不断收到以下错误:

Cannot create a table without columns (does 'PersonModel' have public properties?)无法创建没有列的表(“PersonModel”是否具有公共属性?)

I have a class PersonModel that I want to be immutable, however SQLite is telling me that PersonModel must be mutable, eg each property must use public set;我有一个我想要不可变的 class PersonModel ,但是 SQLite 告诉我PersonModel必须是可变的,例如每个属性都必须使用public set; . .

How can I continue using SQLite.NET with immutable properties?如何继续使用具有不可变属性的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
}

Explanation解释

That error is happening because SQLite.NET uses Reflection to initialize the objects it retrieves from our database, and Reflection requires public set;发生该错误是因为 SQLite.NET 使用Reflection来初始化它从我们的数据库中检索的对象,而 Reflection 需要public set; to initialize each property.初始化每个属性。

Answer回答

We can take advantage of Init-Only Setters , new in C# 9.0 .我们可以利用C# 9.0中新增的Init-Only Setters

Init-Only Setters allow us to define properties that can be set during initialization, AND cannot be changed. Init-Only Setters 允许我们定义可以在初始化期间设置的属性,并且不能更改。 In other words init-only setters let us create immutable objects, AND they allow Reflection to create Immutable Objects!换句话说,init-only setter 让我们创建不可变对象,并且它们允许反射创建不可变对象!

I go deeper into this topic in this blog post: https://codetraveler.io/2020/11/11/using-immutable-objects-with-sqlite.net/我 go 在这篇博文中更深入地探讨了这个主题: 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:删除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
}

Another option is to create a PersonDto class that does all of the SQLite interactions:另一种选择是创建一个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; }
}

Then the Person class encapsulates the DTO object:然后Person class封装了DTO object:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM