在 react-native 中打开预填充的 SQLite 数据库,将数据库放在哪里?

Posted

技术标签:

【中文标题】在 react-native 中打开预填充的 SQLite 数据库,将数据库放在哪里?【英文标题】:Open prepopulated SQLite data base in react-native, where to put database? 【发布时间】:2018-02-28 16:46:54 【问题描述】:

我正在按照说明将现有数据库导入我的应用程序 (ios):https://www.npmjs.com/package/react-native-sqlite

已在 myProject 目录中创建 www 文件夹,放入 myDataBase。 将文件夹添加到 xcode。

这是我打开它并进行查询的源代码:

import SQLite from 'react-native-sqlite-storage'

function errorCB(err) 
  console.log("SQL Error: " + err);


function successCB() 
  console.log("SQL executed fine");


function openCB() 
  console.log("Database OPENED");


console.log('database.js')

var db = null;

export function openDB() 
// var db = SQLite.openDatabase("test.db", "1.0", "Test Database", 200000, openCB, errorCB);
db = SQLite.openDatabase(name : "words", createFromLocation : 1, openCB,errorCB);



export function getWord(str) 
  db.transaction((tx) => 
    tx.executeSql("SELECT * FROM words", [], (tx, results) => 
        console.log("Query completed");

        // Get rows with Web SQL Database spec compliance.

        var len = results.rows.length;
        console.log('len' + len)
        for (let i = 0; i < len; i++) 
          let row = results.rows.item(i);
          console.log(`word: $row.str, Dept Name: $row.smth`);
        

        // Alternatively, you can use the non-standard raw method.

        /*
          let rows = results.rows.raw(); // shallow copy of rows Array

          rows.map(row => console.log(`Employee name: $row.name, Dept Name: $row.deptName`));
        */
      );
  );

我得到:

Built path to pre-populated DB asset from app bundle www subdirectory: /Users/mac/Library/Developer/CoreSimulator/Devices/06420F74-0E1C-47C1-BCAC-5D3574577349/data/Containers/Bundle/Application/75EE8E9A-276F-402F-982A-DBF30DE80802/MyApp.app/www/words
RCTLog.js:48 target database location: nosync
RCTLog.js:48 Opening db in mode READ_WRITE, full path: /Users/mac/Library/Developer/CoreSimulator/Devices/06420F74-0E1C-47C1-BCAC-5D3574577349/data/Containers/Data/Application/67D2451F-3D72-4B82-AC90-AD6DB9A82566/Library/LocalDatabase/words

Database opened
RCTLog.js:48 Good news: SQLite is thread safe!
dataBase.js:13 Database OPENED
RCTLog.js:48 open cb finished ok
sqlite.core.js:475 Error handler not provided:  message: "no such table: words", code: 5
sqlite.core.js:572 warning - exception while invoking a callback: "code":5

不知道这个错误的原因是什么? 我已经在 SQLite 的数据库浏览器中检查了数据库是正确的,并且其中存在表“单词”并且其中有行。 我为 db 文件尝试了不同的名称:'words'、'words.db'、'words.sqlite' 没有任何帮助。

我从控制台运行我的应用程序:

react-native run-ios

【问题讨论】:

你找到解决办法了吗?? 我收到此错误:未定义不是对象(正在评估“db.transaction”) @DivyaThakkar 你可以按照以下解决方案一次github.com/andpor/react-native-sqlite-storage/issues/… 【参考方案1】:
SQLite.openDatabase(name:"testDB.sqlite3", createFromLocation:1,location:'Library')

这解决了我的问题。 testDB.sqlite3 文件大小为 24 MB。 testDB.sqlitetestDB.db 不工作,但 testDB.sqlite3 工作。

【讨论】:

【参考方案2】:

我在这里建立了一个存储库,它可以帮助你

import BaseModule from '../baseModule';
import * as SQLite from 'expo-sqlite';
import * as MediaLibrary from 'expo-media-library';
import * as FileSystem from 'expo-file-system';
import * as Permissions from 'expo-permissions';
import DetaliItemsSettings from '../detaliItemSettings';
import ChapterSettings from '../chapterSettings';
import httpClient from '../http';

export type NovelReaderSettingsType = (items: BaseModule) => void;
export type Find = (foundItems: BaseModule[]) => void;
export default class Repository 
  static dbIni: Boolean;
  databaseName: string;
  constructor() 
    this.databaseName = 'test.db';
  

  importSettings = async (uri: string) => 
    try 
      const status = await Permissions.askAsync(Permissions.MEDIA_LIBRARY);
      if (status === 'granted') 
        var json = await FileSystem.readAsStringAsync(uri, encoding: 'utf8');
        if (json) console.log(json);
        var item = JSON.parse(json) as 
          applicationSettings: any;
          items: DetaliItemsSettings[];
        ;
        var appSettings = await this.where('ApplicationSettings');
        if (item.applicationSettings) 
          item.applicationSettings = httpClient.cloneItem(
            appSettings.length > 0 ? appSettings[0] : ,
            item.applicationSettings,
            ['id', 'tableName'],
          );
          await this.save(
            item.applicationSettings,
            undefined,
            'ApplicationSettings',
          );
        

        if (item.items && item.items.length > 0) 
          for (var i = 0; i < item.items.length; i++) 
            var a = item.items[i];
            var b = (await this.where('DetaliItems', 
              novel: a.novel,
            )) as DetaliItemsSettings[];
            var aChapterSettings =
              a.chapterSettings ?? ([] as ChapterSettings[]);
            var bChaptersSettings =
              b && b.length > 0
                ? ((await this.where('Chapters', 
                    detaliItem_Id: b[0].id,
                  )) as ChapterSettings[])
                : ([] as ChapterSettings[]);
            var updatedChapterSettings = [] as ChapterSettings[];
            if (b && b.length > 0) 
              if (a.chapterIndex) b[0].chapterIndex = a.chapterIndex;
              b[0].isFavorit = true;
              a = b[0];
            

            aChapterSettings.forEach((x) => 
              var bCh = bChaptersSettings.find(
                (a) => a.chapterUrl === x.chapterUrl,
              );
              if (bCh)
                updatedChapterSettings.push(
                  httpClient.cloneItem(bCh, x, ['id', 'tableName']),
                );
              else updatedChapterSettings.push(x);
            );

            let detaliItemSettings = await this.save(
              a,
              undefined,
              'DetaliItems',
            );

            for (var y = 0; y <= aChapterSettings.length - 1; y++) 
              let m = aChapterSettings[y];
              m.detaliItem_Id = detaliItemSettings.id;
              await this.save(m, undefined, 'Chapters');
            
          
        

        return true;
      
     catch (error) 
      console.log(error);
    
    return false;
  ;

  exportFileToDownloadFolder = async () => 
    try 
      const status = await Permissions.askAsync(Permissions.MEDIA_LIBRARY);
      if (status === 'granted') 
        var favoriteData = (await this.where('DetaliItems', 
          isFavorit: true,
        )) as DetaliItemsSettings[];
        for (var i = 0; i < favoriteData.length; i++) 
          var item = favoriteData[i];

          item.chapterSettings = (await this.where('Chapters', 
            detaliItem_Id: item.id,
          )) as ChapterSettings[];
          item.id = 0;
          item.chapterSettings.forEach((x) => 
            x.id = 0;
            x.detaliItem_Id = 0;
          );
        

        var result = 
          applicationSettings:
            (await this.where('ApplicationSettings')).length > 0
              ? (await this.where('ApplicationSettings'))[0]
              : undefined,
          items: favoriteData,
        ;

        let fileUri = FileSystem.documentDirectory + 'NovelManager.db';
        await FileSystem.writeAsStringAsync(fileUri, JSON.stringify(result), 
          encoding: FileSystem.EncodingType.UTF8,
        );
        const asset = await MediaLibrary.createAssetAsync(fileUri);
        await MediaLibrary.createAlbumAsync('Download', asset, false);

        return true;
      
     catch (error) 
      console.log(error);
    
    return false;
  ;

  dataBasePath = () => 
    return FileSystem.documentDirectory + this.databaseName;
  ;
  createConnection = () => 
    return SQLite.openDatabase(this.databaseName);
  ;

  allowedKeys = (tableName: string) => 
    return new Promise((resolve, reject) => 
      this.createConnection().transaction(
        (x) =>
          x.executeSql(
            `PRAGMA table_info($tableName)`,
            undefined,
            (trans, data) => 
              var keys = [] as string[];
              for (var i = 0; i < data.rows.length; i++) 
                if (data.rows.item(i).name != 'id')
                  keys.push(data.rows.item(i).name);
              
              resolve(keys);
            ,
          ),
        (error) => 
          reject(error);
        ,
      );
    ) as Promise<string[]>;
  ;

  selectLastRecord = async (item: BaseModule) => 
    console.log('Executing SelectLastRecord...');
    return (
      await this.find(
        item.id <= 0
          ? `SELECT * FROM $item.tableName ORDER BY id DESC LIMIT 1;`
          : `SELECT * FROM $item.tableName WHERE id=?;`,
        item.id > 0 ? [item.id] : undefined,
      )
    ).map((x) => 
      x.tableName = item.tableName;
      return x;
    );
  ;

  delete = async (item: BaseModule, tableName?: string) => 
    tableName = item.tableName ?? tableName;
    var q = `DELETE FROM $tableName WHERE id=?`;
    await this.execute(q, [item.id]);
  ;

  public save = (
    item: BaseModule,
    insertOnly?: Boolean,
    tableName?: string,
  ) => 
    if (!item.tableName) item.tableName = tableName ?? '';
    return new Promise(async (resolve, reject) => 
      try 
        await this.setUpDataBase();
        console.log('Executing Save...');
        var items = await this.where(item.tableName, id: item.id);
        var keys = (await this.allowedKeys(item.tableName)).filter((x) =>
          Object.keys(item).includes(x),
        );
        let query = '';
        let args = [] as any[];
        if (items.length > 0) 
          if (insertOnly) return;
          query = `UPDATE $item.tableName SET `;
          keys.forEach((k, i) => 
            query += ` $k=? ` + (i < keys.length - 1 ? ',' : '');
          );
          query += ' WHERE id=?';
         else 
          query = `INSERT INTO $item.tableName (`;
          keys.forEach((k, i) => 
            query += k + (i < keys.length - 1 ? ',' : '');
          );
          query += ') values(';
          keys.forEach((k, i) => 
            query += '?' + (i < keys.length - 1 ? ',' : '');
          );
          query += ')';
        
        keys.forEach((k: string, i) => 
          args.push(item[k] ?? null);
        );
        if (items.length > 0) args.push(item.id);

        await this.execute(query, args);
        resolve((await this.selectLastRecord(item))[0]);
       catch (error) 
        console.log(error);
        reject(error);
      
    ) as Promise<BaseModule>;
  ;

  public find = (query: string, args?: any[]) => 
    return new Promise((resolve, reject) => 
      this.createConnection().transaction(
        async (x) => 
          await this.setUpDataBase();
          console.log('Executing Find..');
          x.executeSql(
            query,
            args,
            async (trans, data) => 
              console.log('query executed:' + query);
              var items = [] as BaseModule[];
              for (var i = 0; i < data.rows.length; i++) 
                var t = data.rows.item(i);
                items.push(t);
              
              resolve(items);
            ,
            (_ts, error) => 
              console.log('Could not execute query:' + query);
              console.log(error);
              reject(error);
              return false;
            ,
          );
        ,
        (error) => 
          console.log(error);
          reject(error);
        ,
      );
    ) as Promise<BaseModule[]>;
  ;

  where = async (tableName: string, query?: any) => 
    var q = `SELECT * FROM $tableName $query ? 'WHERE ' : ''`;
    var values = [] as any[];
    if (query) 
      Object.keys(query).forEach((x, i) => 
        q += x + '=? ' + (i < Object.keys(query).length - 1 ? 'AND ' : '');
        values.push(query[x]);
      );
    
    return (await this.find(q, values)).map((x) => 
      x.tableName = tableName;
      return x;
    );
  ;

  findOne = async (tableName: string, query?: any) => 
    var items = await this.where(tableName, query);
    return items && items.length > 0 ? items[0] : undefined;
  ;

  execute = async (query: string, args?: any[]) => 
    return new Promise((resolve, reject) => 
      this.createConnection().transaction(
        (tx) => 
          console.log('Execute Query:' + query);
          tx.executeSql(
            query,
            args,
            (tx, results) => 
              console.log('Statment has been executed....' + query);
              resolve(true);
            ,
            (_ts, error) => 
              console.log('Could not execute query');
              console.log(args);
              console.log(error);
              reject(error);
              return false;
            ,
          );
        ,
        (error) => 
          console.log('db executing statement, has been termineted');
          console.log(args);
          console.log(error);
          reject(error);
          throw 'db executing statement, has been termineted';
        ,
      );
    );
  ;

  public dropTables = async () => 
    await this.execute(`DROP TABLE if exists ApplicationSettings`);
    await this.execute(`DROP TABLE if exists DetaliItems`);
    await this.execute(`DROP TABLE if exists Chapters`);
    Repository.dbIni = false;
    await this.setUpDataBase();
  ;

  setUpDataBase = async () => 
    let applicationSetupQuery = `CREATE TABLE if not exists ApplicationSettings (
      id    INTEGER NOT NULL UNIQUE,
      backGroundColor   TEXT NOT NULL,
      fontSize INTEGER NOT NULL,
      lineHeight INTEGER NOT NULL,
      fontFamily TEXT NOT NULL,
      marginLeft INTEGER NOT NULL,
      marginRight INTEGER NOT NULL,
      detaliItem_Id INTEGER,
      selectedParserIndex INTEGER,
      PRIMARY KEY(id AUTOINCREMENT)
    );`;

    let detaliItemsQuery = `CREATE TABLE if not exists DetaliItems (
      image TEXT NOT NULL,
      title TEXT NOT NULL,
      description   TEXT NOT NULL,
      novel TEXT NOT NULL,
      parserName TEXT NOT NULL,
      chapterIndex INTEGER NOT NULL,
      id INTEGER NOT NULL,
      isFavorit INTEGER NOT NULL,
      PRIMARY KEY(id AUTOINCREMENT)
    );`;

    let chapterQuery = `CREATE TABLE if not exists Chapters (
      id INTEGER NOT NULL UNIQUE,
      chapterUrl TEXT NOT NULL,
      isViewed INTEGER NOT NULL,
      currentProgress   NUMERIC NOT NULL,
      finished INTEGER NOT NULL,
      detaliItem_Id INTEGER NOT NULL,
      PRIMARY KEY(id AUTOINCREMENT),
      CONSTRAINT "fk_detaliItem_id" FOREIGN KEY(detaliItem_Id) REFERENCES DetaliItems(id)
    );`;

    if (!Repository.dbIni) 
      console.log('dbIni= false, setUpDataBase');
      await this.execute(applicationSetupQuery);
      await this.execute(detaliItemsQuery);
      await this.execute(chapterQuery);
      Repository.dbIni = true;
     else 
      console.log('dbIni= true, setUpDataBase');
    
  ;

【讨论】:

以上是关于在 react-native 中打开预填充的 SQLite 数据库,将数据库放在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

sqlite3 没有第二次打开预填充的数据库

自动打开默认电子邮件客户端并预填充内容

在 react-native 中运行脚本预构建

预填充Google地图自动填充功能(iOS / Swift)

<REACT-NATIVE> 从预捆绑文件加载,我想从端口:8081 加载,id 怎么办?

如何在房间数据库中预填充数据