如何将GUID用作System.Data.Sqlite的主键

时间:2016-10-12 16:06:00

标签: sqlite system.data.sqlite

我并不是说这是可取的,但有时你会继承一些只需要工作的东西。在这种情况下,它是主键的指南......

开箱即用,您将收到有关System.Guid无法使用byte []的错误(如果您使用BinaryGUID = False,则会收到字符串)。

1 个答案:

答案 0 :(得分:2)

要解决此问题,您需要拦截byte []数组(或字符串),而是返回Guid类型。这可以通过System.Data.Sqlite提供程序实现。

第一

using System.Data.SQLite;

然后,将它放在代码优先的db上下文的构造函数中:

var con = (SQLiteConnection)base.Database.Connection;
var bind = System.Data.SQLite.SQLiteTypeCallbacks.Create(
                null, 
                new SQLiteReadValueCallback(GuidInterceptor), null, null);
con.SetTypeCallbacks("uniqueidentifier", bind);
con.SetTypeCallbacks("", bind); //Sometimes, the system just doesn't know
con.Flags |= SQLiteConnectionFlags.UseConnectionReadValueCallbacks;

然后这是神奇的功能:

    private void GuidInterceptor(SQLiteConvert convert, SQLiteDataReader reader, SQLiteConnectionFlags flags, SQLiteReadEventArgs args, string typename, int index, object userdata, out bool complete)
    {
        complete = false;
        if (typename == "uniqueidentifier")
        {
            var e = (SQLiteReadValueEventArgs)args;

            var o = reader.GetGuid(index);
            e.Value.Value = o;
            e.Value.GuidValue = o;
            complete = true;
        }
        else
        {
            var o = reader.GetValue(index);
            if (o is byte[])
            {
                var b = (byte[])o;
                if (b.Length == 16)
                {
                    var e = (SQLiteReadValueEventArgs)args;
                    var g = new Guid(b);
                    e.Value.Value = g;
                    e.Value.GuidValue = g;
                    complete = true;
                }
            }
            else if (o is string)
            {
                var s = (string)o;
                if (s.Length == 36)
                {
                    var e = (SQLiteReadValueEventArgs)args;
                    var goGuid = (e.MethodName == "GetGuid");
                    if (!goGuid)
                        goGuid = (s[8] == '-' && s[13] == '-' && s[18] == '-' && s[23] == '-');

                    Guid g;
                    if (goGuid && Guid.TryParse(s, out g))
                    {
                        e.Value.Value = g;
                        e.Value.GuidValue = g;
                        complete = true;
                    }
                    else
                    {

                    }

                }
            }
        }

    }

这只能修复数据的读入。如果您在Guid成员上尝试.Where(),并且您正在使用BinaryGUID=True,则不会返回任何行(应该有)。目前,您需要BinaryGUID=False,这会占用更多空间,但这是一个简单的解决方案。

如果您可以提供帮助,请尝试将您的Guid属性定义为:

[Key]
[MaxLength(16)]
[MinLength(16)]
public byte[] AccountUserId { get; set; }

您将被迫在应用层中呼叫guidValue.ToByteArray()。您可以创建一些帮助程序,而不必调用该函数。拥有自己的自定义函数代理来创建和解析Guids可能会有所帮助,因此您可以轻松地更改实现。

就我而言,我没有足够的时间将所有Guid属性和用法转换为byte[]