2016-10-12 6 views
1

Я не говорю, что это целесообразно, но иногда вы наследуете то, что просто нужно работать. В этом случае это Guids for PKs ...Как использовать GUID как основной ключ с System.Data.Sqlite

Из системы вы получите сообщение об ошибке System.Guid, не работающей с байтом [] (или String, если вы используете BinaryGUID = False).

ответ

1

Чтобы исправить это, вам нужно перехватить байт [] массивы (или строки) и вместо этого вернуть тип Guid. Это возможно с поставщиком System.Data.Sqlite.

Первый

using System.Data.SQLite; 

Затем поместите это в конструкторе кода-первых дб контексте:

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 
        { 

        } 

       } 
      } 
     } 

    } 

Это только фиксирует чтение данных. Если вы попытаетесь использовать .Where() в элементе Guid, и вы используете BinaryGUID=True, никакие строки не будут возвращены (когда они должны быть). На данный момент вам понадобится BinaryGUID=False, что занимает больше места, но это простое решение.

Если вы можете помочь ему, попытаться определить свои свойства Guid вместо как:

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

Вы будете вынуждены вызвать guidValue.ToByteArray() в вашем прикладном уровне. Возможно, вы сможете создать некоторые помощники, вам не нужно будет вызывать эту функцию. Наличие собственного прокси-сервера для создания и анализа Guids может помочь, поэтому вы можете легко изменить реализацию.

В моем случае у меня нет роскоши времени, чтобы преобразовать все свойства и обычаи Guid, чтобы byte[]