简体   繁体   English

在 C# 中为 SQLite 形成数据结构的问题

[英]Trouble forming data structure for SQLite in C#

I am trying to build a very simple Xamarin app that functions similarly to a Exercise/Day Planner.我正在尝试构建一个非常简单的 Xamarin 应用程序,其功能类似于锻炼/日计划。 The SQLite database should hold a "Day"s table, and every day should relate to an "Activity"s table which it can query that days "Activity"s. SQLite 数据库应该保存一个“Day”s 表,并且每一天都应该与一个“Activity”s 表相关联,它可以查询那几天的“Activity”s。 These "Activity"s should be of a certain type, for simplicity lets say either "Walk", "Run" or "Swim".这些“活动”应该属于某种类型,为简单起见,我们可以说“步行”、“跑步”或“游泳”。 The user should then be able to perform basic CRUD operations on this database to recall previous days and it's associated activities.然后,用户应该能够对该数据库执行基本的 CRUD 操作,以回忆前几天及其相关活动。 Ideally, using the SQLiteNetExtensions library, I should be able to make a simple call to retrieve data:理想情况下,使用 SQLiteNetExtensions 库,我应该能够进行简单的调用来检索数据:

SQLiteAsyncConnection connection = DependencyService.Get<ISQLiteDb>().GetConnection();
var day = await connection.GetWithChildrenAsync<Day>(primaryKey, recursive = true);

Models (simplified):模型(简化):

using SQLite;
using SQLiteNetExtensions.Attributes;
using System;
using System.Collections.Generic;

public class Day {

    public Day()
    {
        Date = DateTime.Now;
    }

    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    public DateTime Date { get; set; }

    [OneToMany]
    public List<Activity> Activities { get; set; }
}

public abstract class Activity
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    [ManyToOne(typeof(Day))]
    public Day Day { get; set; }

    [ForeignKey]
    public int DayRefId { get; set; }

    public double Input { get; set; }

    public virtual double OutputKms { get; set; }
}

public class Walk : Activity 
{
    public override double OutputKms { get { return Input * 3; } }
}

public class Run: Activity 
{
    public override double OutputKms { get { return Input * 5; } }
}

public class Swim: Activity 
{
    public override double OutputKms { get { return Input * 3; } }
}

I am initializing my database with the following code:我正在使用以下代码初始化我的数据库:

using SQLite;
using Xamarin.Forms;
using SQLiteNetExtensionsAsync.Extensions;    

public async static Task InitDb()
{
    SQLiteAsyncConnection connection = DependencyService.Get<ISQLiteDb>().GetConnection();

    await connection.CreateTableAsync<Day>();
    await connection.CreateTableAsync<Activity>();
    await connection.CreateTableAsync<Walk>();
    await connection.CreateTableAsync<Run>();
    await connection.CreateTableAsync<Swim>();
}

The problem is that SQLite doesn't like tables based on abstract classes.问题是 SQLite 不喜欢基于抽象类的表。 On the line where I try to create the "Activity" table I get the following compilation error:在我尝试创建“活动”表的行中,我收到以下编译错误:

Error CS0310 'Activity' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T'错误 CS0310“活动”必须是具有公共无参数构造函数的非抽象类型才能将其用作参数“T”

I know working with abstract classes is supported in Entity Framework but I would rather stick to using SQLite if possible.我知道实体框架支持使用抽象类,但如果可能,我宁愿坚持使用 SQLite。

This seems like a simple problem but has been tricky for me to work out without resorting to the simplest poco objects and writing lots of repetitive code.这似乎是一个简单的问题,但对我来说,在不求助于最简单的 poco 对象和编写大量重复代码的情况下解决起来很棘手。

My question is how can I better restructure my code, what libraries can I use or what kind of mapping can I write in order to implement this.我的问题是如何更好地重构我的代码,我可以使用哪些库或我可以编写什么样的映射来实现这一点。 Appreciate any feedback.感谢任何反馈。 Thank you!谢谢!

All of the types in Sqlite.net and Sqlite.net Extensions are T : new() so you are not going to be able to use abstract classes. Sqlite.net 和 Sqlite.net 扩展中的所有类型都是T : new()所以你不能使用抽象类。 Code like this:像这样的代码:

[OneToMany]
public List<Activity> Activities { get; set; }

where Activity is an abstract class is not going to work, as it would be very hard to work out what table the data should come from.其中Activity是一个抽象类是行不通的,因为很难确定数据应该来自哪个表。

It may construct the tables for Activity , Walk , Swim , Run (If you make the Activity not abstract) but Sqlite.net Extensions won't be able to create the relationships and thus won't pull back the data.它可能会为ActivityWalkSwimRun构建表(如果您使Activity不是抽象的),但 Sqlite.net 扩展将无法创建关系,因此不会拉回数据。

Personally I wouldn't have the logic of this property in the model that you are persisting, (You may have done this to simplify the question and there is more logic):就我个人而言,我不会在您坚持的模型中拥有此属性的逻辑(您可能这样做是为了简化问题,并且有更多逻辑):

public override double OutputKms { get { return Input * 3; } }

You could refactor to have whatever the multiplier of 3, 5, 3 in Walk , Run , Swim out to property or store an activity type enum in the activity class and not make it abstract like:您可以将WalkRunSwim的乘数重构为属性或在活动类中存储活动类型枚举,而不是将其抽象为:

public class Activity
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    [ManyToOne(typeof(Day))]
    public Day Day { get; set; }

    [ForeignKey]
    public int DayRefId { get; set; }

    public double Input { get; set; }

    public ActivityType ActivityType { get; set; }
}

public enum ActivityType
{
    Walk,
    Run,
    Swim
}

Another option would be to create different models for the database that are Pocos that map to the more complex app models.另一种选择是为 Pocos 数据库创建不同的模型,这些模型映射到更复杂的应用程序模型。 Possibly using AutoMapper可能使用 AutoMapper

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

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