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

C# 如何将外键映射到SQLite Net Extensions中的对象字段?,c#,sqlite,c#-4.0,sqlite-net,sqlite-net-extensions,C#,Sqlite,C# 4.0,Sqlite Net,Sqlite Net Extensions,上下文: 我们使用SQLite-Net-Extensions与Xamarin进行本地数据缓存。我们计划部署到iOS、Android和Windows Phone。我们在整个系统中使用了现有的数据结构(都实现了一个公共接口),我们希望以这种方式存储这些数据结构 问题 如代码示例所示,[manytone]属性用于表示关系字段。这是行不通的。如上所述,[ForeignKey]属性可用于指定外键关系。这似乎只支持int。我们可以很容易地调整结构以支持这些关系,而不必重复Id字段的属性。e、 g.以下情况是

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

问题 如代码示例所示,
[manytone]
属性用于表示关系字段。这是行不通的。如上所述,
[ForeignKey]
属性可用于指定外键关系。这似乎只支持
int
。我们可以很容易地调整结构以支持这些关系,而不必重复Id字段的属性。e、 g.以下情况是不可取的

    [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在这方面也没有什么不同。因此,SQLite Net和SQLite Net扩展还使用外键机制来声明关系

作为替代方案,您可以使用中间表来存储关系,这与
manytomy
关系的工作方式相同,但将一端限制为一端。这样,您可以使用多个关系和中间表来模拟一个
OneToMany
ManyToOne
甚至
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; }
}
[表(“客户端”)]
公共类客户端{
[主密钥,自动递增,列(“\u id”)]
公共int Id{get;set;}
[忽略]//不应持久化此属性
公共广播地址{get;set;}
//这种关系实际上是一种多人关系,
//但我们将其建模为多个,以避免向该实体添加外键
[ManyToMany(类型(地址客户))]
公共广播[]地址{
获取{返回地址!=null?新[]{Address}:Address;}
设置{Address=value.FirstOrDefault();}
}
}
[表(“地址”)]
公共课堂演讲
{
[主密钥,自动递增,列(“\u id”)]
公共int Id{get;set;}
公共字符串SomeFields{get;set;}
[ManyToMany(typeof(AddresseSClient),ReadOnly=true]
公共列表客户端{get;set;}
}
//定义地址和客户端之间关系的中间表
类地址客户端{
[主密钥,自动增量]
公共int Id{get;set;}
[外键(客户类型))]
public int ClientId{get;set;}
[外键(类型(地址))]
public int AddressId{get;set;}
}
当然,这会对性能造成一些影响


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

虽然这不是我们选择的解决方案,但它是类似的。在本例中,我们分叉了sqlite net extensions存储库并对其进行了修改。我们添加了一个新的自定义属性来指示外键。然后,我们修改了内部读/写操作,以便每次检测到属性时,它都会写入自定义关系表,存储:源表、字段、对象id和目标对象id。