[英]Checking if data exist in sqlite-net before inserting them to database
我正在制作一个将使用“模板”的 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 对象在我的数据库中都是唯一的,属性Unique不做任何事情,因为我猜是因为 TemplateImage 表有一个自动增量 Id 将始终是唯一的,无论 Image 或 ImageHash 在 2 条记录中是否相同。
我当时在想,我还能如何确保TemplateImages是唯一的(注意:当我说唯一时,我的意思是没有任何其他List具有每个TemplateImage的确切图像,顺序相同)。
此外,我使用图像的 ResourceID 作为图像,这是错误的,因为它们可能会在每次新编译的应用程序更新时更改。
所以我决定从图像中制作一个哈希 md5。 我发现在Xamarin.Android 中加载资源图像(我的图像是矢量 .xml文件)的唯一方法是将资源转换为位图,然后将位图转换为字节,然后将字节转换为 md5。
而且我也应该有一个模板项的哈希字符串。 所以我通过将图像的所有字节 [] 合并为一个,然后将其合并,为模板创建了一个 md5 哈希。
我为这项工作创建了这个疯狂的代码:
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列表(无法避免),那么为什么不给他们我的自己的字符串哈希码并比较它以查找是否存在记录?
正确的做法是什么?
最后,我想使用guid作为额外的id 字段并添加参数 unique,在这种情况下,我可以确定插入了哪些模板,但我决定使用事务。 通过事务,我可以知道我的所有数据是创建还是没有创建,并将创建的内容保存到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 ,如果需要任何创建,它就会发生。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.