c# - 如何将外键映射到 SQLite-Net Extensions 中的对象字段?

标签 c# sqlite c#-4.0 sqlite-net sqlite-net-extensions

上下文: 我们使用 SQLite-Net Extensions 通过 Xamarin 进行本地数据缓存。我们计划部署到 iOS、Android 和 Windows Phone。我们在整个系统中使用了现有的数据结构(全部实现了一个通用接口(interface)),我们希望以这种方式存储。

问题 如代码示例所示,[ManyToOne] 属性用于表示关系字段。这是行不通的。如 BitBucket Developer Page 中所述[ForeignKey] 属性可用于指定外键关系。这似乎只支持int。我们是否可以轻松地调整我们的结构来支持这些关系,而无需复制 Id 字段的属性?例如以下是不可取的。

    [ForeignKey(typeof(Address))]
    public int AddressId { set; get; }

    [ManyToOne]
    public Address Address
    {
        set { address = value; }
        get { return address; }
    }

代码示例

using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;

namespace Data
{
    [Table("Client")]
    public class Client : IData
    {
        private int id = -1;
        private Address address = null;

        public Client() { }

        public Client(int id)
        {
            this.id = id;
        }

        [PrimaryKey, AutoIncrement, Column("_id")]
        public int Id
        {
            set { id = value; }
            get { return id; }
        }

        [ManyToOne]
        public Address Address
        {
            set { address = value; }
            get { return address; }
        }
    }

    [Table("Address")]
    public class Address : IIdentifiable
    {
        private int id = -1;
        private string someFields = "";

        public Address() { }

        public Address(int id)
        {
            this.id = id;
        }

        [PrimaryKey, AutoIncrement, Column("_id")]
        public int Id
        {
            set { id = value; }
            get { return id; }
        }

        public string SomeFields
        {
            set { someFields = value; }
            get { return someFields; }
        }
    }
}

最佳答案

SQLite-Net Extensions 是 SQLite-Net 上的一个薄层,它使用 sqlite 数据库进行存储。关系数据库使用外键存储关系,sqlite 在这方面也不异常(exception)。因此,SQLite-Net 和 SQLite-Net Extensions 也使用外键机制来声明关系。

作为一种替代方案,您可以使用中间表来存储关系,与ManyToMany 关系的工作方式相同,但将其中一端限制为一个。这样,您就可以使用 ManyToMany 关系和中间表来模拟 OneToManyManyToOne 甚至 OneToOne 关系。例如:

[Table("Client")]
public class Client {

    [PrimaryKey, AutoIncrement, Column("_id")]
    public int Id { get; set; }

    [Ignore] // This property shouldn't be persisted
    public Address Address { get; set; }

    // This relationship is in fact a ManyToOne relationship,
    // but we model it as a ManyToMany to avoid adding foreign key to this entity
    [ManyToMany(typeof(AddressesClients))]
    public Address[] Addresses { 
        get { return Address != null ? new []{ Address } : Address; } 
        set { Address = value.FirstOrDefault(); }
    }
}

[Table("Address")]
public class Address
{
    [PrimaryKey, AutoIncrement, Column("_id")]
    public int Id { get; set; }

    public string SomeFields { get; set; }

    [ManyToMany(typeof(AddressesClients), ReadOnly = true)]
    public List<Client> Clients { get; set; }
}

// Intermediate table that defines the relationship between Address and Client
class AddressesClients {
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    [ForeignKey(typeof(Client))]
    public int ClientId { get; set; }

    [ForeignKey(typeof(Address))]
    public int AddressId { get; set; }
}

当然,这会带来一些性能损失。

对于 PrimaryKey,您可以使用任何受支持的类型,并且您必须对相反的 ForeignKey 使用完全相同的类型,即如果您使用 Guid 作为主键,指向该类的外键也必须是Guid。在演示项目中,我们已经使用了 int(性能最佳)、string 甚至 UUID

关于c# - 如何将外键映射到 SQLite-Net Extensions 中的对象字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33261419/

相关文章:

android - 启动第三个 Activity 时崩溃

sql - SQLite 中的 GROUP_CONCAT

asp.net - 当计时器事件正在运行且按钮单击事件触发时,如何停止计时器

c# - 具有标志属性的枚举

c# - 有没有办法根据平台向 C#/Unity 中的属性添加逻辑?

javascript - Hub 方法仅运行一次

c#-4.0 - Nlog 未将所有行写入并行循环中的文件

c# - Python 比 Java/C# 慢吗?

java - 我在 SQLITE 中执行选择时出错

c# - 缺少 .NET 4.0 的引用程序集文件夹