Проверка наличия данных в sqlite- net перед их вставкой в ​​базу данных - PullRequest
0 голосов
/ 09 марта 2020

Я создаю приложение Xamarin. Android, которое будет использовать «шаблоны», шаблон таков:

[Table("Templates")]
    public class Template
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
        public int Category { get; set; }
        //[TextBlob("imagesBlobbed")]
        [OneToMany, Unique]
        public List<TemplateImage> TemplateImages { get; set; }
        public string ImagesHash { get; set; }
        //public string imagesBlobbed { get; set; }
    }
    [Table("TemplateImages")]
    public class TemplateImage
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
        public int Category { get; set; }
        public string ImagesHash { get; set; }
        public int Image { get; set; }
        [ForeignKey(typeof(Template))]
        public int TemplateId { get; set; }
    }

я хочу, чтобы все объекты TemplateImages были уникальными в моей базе данных, атрибут Уникальный ничего не делает, потому что я думаю, потому что в таблице TemplateImage идентификатор автоинкремента всегда будет уникальным, независимо от того, одинаковы ли Image или ImageHa sh в 2 записях.

Я думал тогда как еще я могу быть уверен, что TemplateImages будет уникальным ( Notice : когда я говорю уникально, я имею в виду, что нет никакого другого List , который имеет точное изображение для каждого TemplateImage , в том же порядке).

Также я использовал ResourceID изображений, как изображения, что неверно, поскольку они могут измениться при каждом новом обновлении скомпилированного приложения.

Поэтому я решил сделать ха sh md5 из изображений. Единственный способ, которым я нашел способ загрузить изображения ресурсов (мои изображения - векторные. xml файлы) в Xamarin. Android - путем преобразования ресурса в растровое изображение, а затем преобразуйте растровое изображение в байт, а затем байт в md5.

А также у меня должна быть строка ha sh для элемента шаблона. поэтому я создаю md5 га sh для шаблона, объединяя все байты [] изображений в одно и затем получая его.

Я создаю этот сумасшедший код для этой работы:

        public static string GetMD5Hash(byte[] content)
        {
            using (var md5 = MD5.Create())
            {
                byte[] computedHash = md5.ComputeHash(Encoding.UTF8.GetBytes(BitConverter.ToString(content).Replace("-", "")));
                return new System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary(computedHash).ToString();
            }
        }

        private static SQLiteConnection instance;
        public static SQLiteConnection db()
        {
            if (instance == null)
                instance = new SQLiteConnection(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TemplatesData.db"));

            return instance;
        }
        public static void CloseConnection()
        {
            if (instance != null)
            {
                instance.Close();
                instance.Dispose();
                instance = null;
            }
        }

    }
    public class TemplateDB
    {
        public static byte[] ConcatByteList(List<byte[]> list)
        {
            return list
                .SelectMany(a => a)
                .ToArray();
        }

        public static Bitmap GetBitmapFromVectorDrawable(Context context, int drawableId)
        {
            Drawable drawable = ContextCompat.GetDrawable(context, drawableId);
            if (Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.Lollipop)
            {
                drawable = (DrawableCompat.Wrap(drawable)).Mutate();
            }

            Bitmap bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth,
                    drawable.IntrinsicWidth, Bitmap.Config.Argb8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.SetBounds(0, 0, canvas.Width, canvas.Height);
            drawable.Draw(canvas);

            return bitmap;
        }

        public byte[] DrawableToByteArray(int resourceId)
        {
            var context = AppState.ApplicationState;
            using (var bitmap = GetBitmapFromVectorDrawable(context, resourceId))
            {
                int size = bitmap.ByteCount;
                byte[] byteArray = new byte[size];
                ByteBuffer byteBuffer = ByteBuffer.Allocate(size);
                bitmap.CopyPixelsToBuffer(byteBuffer);
                byteBuffer.Rewind();
                byteBuffer.Get(byteArray);
                return byteArray;
            }
        }
        public static void AddTemplate(int category, List<int> images)
        {
            var templateDB = new TemplateDB();
            var imageByteList = new List<byte[]>();

            foreach (int image in images)
            {
                imageByteList.Add(templateDB.DrawableToByteArray(image));
            }
            var tmpl = new Template()
            {
                Category = category,
            };
            var img1 = new TemplateImage()
            {
                Category = category,
                Image = images[0],
                ImagesHash = DatabaseHelper.GetMD5Hash(imageByteList[0]),
            };
            var img2 = new TemplateImage()
            {
                Category = category,
                Image = images[1],
                ImagesHash = DatabaseHelper.GetMD5Hash(imageByteList[1]),
            };
            var img3 = new TemplateImage()
            {
                Category = category,
                Image = images[2],
                ImagesHash = DatabaseHelper.GetMD5Hash(imageByteList[2]),
            };
            var img4 = new TemplateImage()
            {
                Category = category,
                Image = images[3],
                ImagesHash = DatabaseHelper.GetMD5Hash(imageByteList[3]),
            };
            var img5 = new TemplateImage()
            {
                Category = category,
                Image = images[4],
                ImagesHash = DatabaseHelper.GetMD5Hash(imageByteList[4]),
            };
            tmpl.TemplateImages = new List<TemplateImage>() { img1, img2, img3, img4, img5 };
            tmpl.ImagesHash = DatabaseHelper.GetMD5Hash(ConcatByteList(imageByteList));
            var result = DatabaseHelper.db().Query<TemplateImage>("Select * from Templates where ImagesHash=?", tmpl.ImagesHash);
            if (result.Count == 0)
            {
            DatabaseHelper.db().InsertAll(tmpl.TemplateImages);
            DatabaseHelper.db().Insert(tmpl);
            DatabaseHelper.db().UpdateWithChildren(tmpl);
            }
        }

Что вдруг выдает из памяти исключение.

Подумав некоторое время о том, что я должен прекратить программирование и начать танцы живота, я думаю, что поскольку я даю в sqlite AddTemplate функцию списка ResourceIds , которые у меня есть чтобы создать вручную (не могу этого избежать), то почему бы не дать им свою собственную строку с кодом sh и сравнить ее, чтобы найти, существует ли запись?

Какой правильный подход?

1 Ответ

0 голосов
/ 10 марта 2020

В конце я подумал об использовании guid в качестве дополнительных идентификаторов полей и добавлении уникального параметра, в этом случае я мог быть уверен, какие шаблоны были вставлены, но я решил использовать транзакций . С транзакциями я могу знать, что все мои данные созданы или нет, а также сохранить создание в переменную в SharedPreferences и избежать повторного создания или даже проверки, если база данных существует.

Для проверки, если данные корректно обновляются, и воссоздание не требуется. Я использовал этот код:

public bool FirstRun { get; set; } = true;
public int DatabaseCreatedVersionOf { get; set; } = -1;

public override void OnCreate()
{
    base.OnCreate();
}

public void UpdateDatabaseCreatedVersion()
{
    DatabaseCreatedVersionOf = Preferences.Get(Settings.DatabaseCreatedVersionOfKey,
       Settings.DatabaseCreatedVersionOfDefault);
}

public void CreateTemplateDB()
{
    UpdateDatabaseCreatedVersion();
    if (DatabaseCreatedVersionOf == -1)
        TemplateDB.CreateDB();
    FirstRun = false;
}
public Template GetTemplateById(int id)
{
    if (FirstRun)
    {
        CreateTemplateDB();
        FirstRun = false;
    }

    return TemplateDB.GetTemplate(id);
}
public List<Template> GetAllTemplates()
{
    if (FirstRun)
    {
        CreateTemplateDB();
        FirstRun = false;
    }

    return TemplateDB.GetAllTemplates();
}

Теперь все, что мне нужно сделать, это вызвать GetTemplateById или GetAllTemplates и, если есть, создание требуется, это произойдет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...