问题描述
我最近注意到有几篇文章提到了用通用代码创建sqlite连接。这是新的东西吗,因为我一直通过接口这样做:
是否有一种方法可以全部用通用代码完成,而不是在下面的需要使用Common,iOS和Android代码的实现中实现?
公用代码:
[assembly: Dependency(typeof(IsqliteDB_iOS))]
namespace Memorise.iOS
{
public class IsqliteDB_iOS : IsqliteDB
{
public (sqlite.sqliteConnection,bool) GetConnection(string _dbname)
{
bool newDb = false ;
var sqliteFilename = _dbname;
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string libraryPath = Path.Combine(documentsPath,"..","Library");
Debug.WriteLine(documentsPath);
Debug.WriteLine(libraryPath);
var path = Path.Combine(libraryPath,sqliteFilename);
switch (_dbname)
{
case CONST.DB1Name:
if (File.Exists(path))
{
newDb = false;
File.Delete(path);
}
else
{
newDb = true;
}
File.copy(sqliteFilename,path);
break;
case CONST.DB2Name:
if (File.Exists(path))
{
newDb = false;
}
else
{
newDb = true;
File.Create(path);
}
break;
case CONST.DB3Name:
if (File.Exists(path))
{
newDb = false;
}
else
{
newDb = true;
File.copy(sqliteFilename,path);
}
break;
}
return (new sqlite.sqliteConnection(path),newDb);
}
}
}
iOS代码:
[assembly: Dependency(typeof(sqliteDB1_Android))]
namespace Memorise.Droid
{
public class sqliteDB1_Android : IsqliteDB1
{
public (sqlite.sqliteConnection,bool) GetConnection()
{
bool newDb;
var sqliteFilename = "db1.db3";
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath,sqliteFilename);
if (File.Exists(path))
{
newDb = false;
File.Delete(path);
}
else
{
newDb = true;
}
FileStream writeStream = new FileStream(path,FileMode.OpenorCreate,FileAccess.Write);
ReadWriteStream(Android.App.Application.Context.Assets.Open(sqliteFilename),writeStream);
return (new sqlite.sqliteConnection(path),newDb);
}
void ReadWriteStream(Stream readStream,Stream writeStream)
{
int Length = 256;
Byte[] buffer = new Byte[Length];
int bytesRead = readStream.Read(buffer,Length);
while (bytesRead > 0)
{
writeStream.Write(buffer,bytesRead);
bytesRead = readStream.Read(buffer,Length);
}
readStream.Close();
writeStream.Close();
}
}
}
Android代码:
{{1}}
解决方法
我们可以利用FileSystem
中的Xamarin.Essentials NuGet Package API来查找特定于平台的App Data Directory并以共享代码创建数据库连接。
var databasePath = Path.Combine(FileSystem.AppDataDirectory,"Database.db3");
var databaseConnection = new SQLiteConnection(databasePath);
我在有关Xamarin + SQLite的博客文章中更加深入:https://codetraveler.io/2019/11/26/efficiently-initializing-sqlite-database/
,正如我看到的代码所示,您有两个数据库文件db1和db2。 此外,我可以看到db1是从Project Assests复制并粘贴到本地文件夹中的。 因此,您需要将db1.db3文件放入Resources文件夹中并将其标记为EmbeddedResource。这一步很重要。
可以简化其余代码,并将其更改为:-
public DataManager()
{
var db1Path = Path.Combine(BasePath,CONST.DB1Name);
newDb1 = !File.Exists(db1Path);
if (newDb1)
{
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(DataManager)).Assembly;
Stream stream = assembly.GetManifestResourceStream("YourProjectName.Resources.db1.db3");
using (var db1SourceStream = new FileStream(db1Path,FileMode.Create,FileAccess.ReadWrite))
{
stream.CopyTo(db1SourceStream);
db1SourceStream.Close();
}
}
db1 = new SQLiteConnection(db1Path);
var db2Path = Path.Combine(BasePath,CONST.DB2Name);
newDb2 = !File.Exists(db2Path);
db2 = new SQLiteConnection(db2Path);
db2.TimeExecution = true;
}
,
通过使用sqlite-net-pcl,我成功地在.NET Standard库中建立了数据层,并在Xamarin Forms(iOS)和WPF中使用了它(但是您可能还可以将其扩展到Android和UWP。例如,
主要技巧是通过使用DI或平台if / else编译为数据库文件的应用程序本地存储指定不同的路径。
还有一个技巧,用于外键和删除级联(“ PRAGMA foreign_keys = ON;”),对于某些平台,在创建Connection对象之后仅调用一次就足够了,但是对于iOS而言,我需要将其更改为在每个需要外键的层叠功能的命令之前被调用。
protected readonly SQLiteAsyncConnection db;
protected abstract List<BaseMigration> Migrations { get; }
public YourDB(string dbPath)
{
db = new SQLiteAsyncConnection(dbPath);
db.ExecuteAsync("PRAGMA foreign_keys=ON;").Wait();
//ExecuteMigrations(db).Wait();
}