Hi I am using SQLite as database in my Unity project. For some reason database file got corrupted but luckily I had backup so I didn't lose anything. I think the reason behind corruption was using unity collab to share database file. My question is what can I do not to corrupt the file again? Also can it corrupt after releasing the game in player's local gamefiles?
And here is the static methods i am using to execute commands, maybe something is wrong with it.
public static void Execute(string command, ref DataTable datatable)
{
string dbPath = ("Data Source=" + Application.dataPath + "/database.s3db");
using (SqliteConnection cnt = new SqliteConnection(dbPath))
{
using (SqliteCommand cmd = new SqliteCommand(command, cnt))
{
using (SqliteDataAdapter adapter = new SqliteDataAdapter(cmd))
{
adapter.Fill(datatable);
}
}
}
}
public static void Execute(string command)
{
string dbPath = ("Data Source=" + Application.dataPath + "/database.s3db");
using (SqliteConnection cnt = new SqliteConnection(dbPath))
{
using (SqliteCommand cmd = new SqliteCommand(command, cnt))
{
cnt.Open();
cmd.ExecuteNonQuery();
cnt.Close();
}
}
}
SQLite implements atomic transactions, but those guarantees hold only as long as the database file is accessed only through the SQLite library.
In your case, it's likely that the database file was copied from your friend's computer in the middle of a transaction, i.e., some changes did not end up in the published version. The only way to avoid this is to ensure that no files are currently being modified when doing the publishing.
Related
Background information
My game is working on iOS, and now trying to update it to work on android. I have a database, Artifact.db, in a StreamingAssets folder, that is built off of SQLite and that has read-only information that I use to get data for the game.
Issue
The core issue is that the SQlite can't read the data, most likely because its not accessible from what I have been reading through on the docs. I am looking for any solutions but preferably something using the UnityWebRequest feature rather than the deprecated WWW
Working iOS Code
// Platform dependent code
string filepath = Application.streamingAssetsPath + "/Artifact.db";
string conn = "URI=file:" + filepath;
// SQlite
IDbConnection dbconn;
IDbCommand dbcmd;
IDataReader reader;
dbconn = (IDbConnection)new SqliteConnection(conn);
dbconn.Open();
dbcmd = dbconn.CreateCommand();
string sqlQuery = $"SELECT * FROM Artifact WHERE Rarity='{type}'";
dbcmd.CommandText = sqlQuery;
reader = dbcmd.ExecuteReader();
Using this code above on android results in error when doing the reader = dbcmd.ExecuteReader(); since it cannot find file.
Attempts at Android code
(Since the SQLite code itself is fine I'll only be including the platform-dependent section which deals with finding the file.)
string DatabaseName = "Artifact.db";
#if UNITY_ANDROID
string filepath = Application.persistentDataPath + "/Artifact.db";
if (!File.Exists(filepath))
{
Debug.Log("Database not in Persistent path");
// if it doesn't ->
// open StreamingAssets directory and load the db ->
var loadDb = new WWW("jar:file://" + Application.dataPath + "!/assets/" + DatabaseName); // this is the path to your StreamingAssets in android
while (!loadDb.isDone) { } // CAREFUL here, for safety reasons you shouldn't let this while loop unattended, place a timer and error check
// then save to Application.persistentDataPath
File.WriteAllBytes(filepath, loadDb.bytes);
}
string conn = "URI=file:" + filepath;
#endif
I also tried the code from this unity forum post. (also modified some things to fit my project)
var loadingRequest = UnityWebRequest.Get(Path.Combine(Application.streamingAssetsPath, "Artifact.db"));
// Used "Artifact.db" instead of "your.bytes"
loadingRequest.SendWebRequest();
while (!loadingRequest.isDone) {
if (loadingRequest.isNetworkError || loadingRequest.isHttpError) {
break;
}
}
if (loadingRequest.isNetworkError || loadingRequest.isHttpError) {
} else {
File.WriteAllBytes(Path.Combine(Application.persistentDataPath , "Artifact.db"), loadingRequest.downloadHandler.data);
// Used "Artifact.db" instead of "your.bytes"
}
string filepath = Application.persistentDataPath + "/Artifact.db";
string conn = "URI=file:" + filepath;
What I am hoping for
I ideally hope to replicate the iOS code. I think this might mean copying the Artifact.db file to somewhere that is persistent and accessible on android and then using that file location to open the file with SQLite.
i have a problem with making a local database into my c# project and creating it..
I tried first with making a Microsoft Sql Server but the problem is that i need to make app which should run on every pc. The app should input data from user , and collect it to the database, and on every start of program, the database should be filled with the leftover of earlier input.. What you suggest me to do?
First to connect your c# application with sqlite you should start with getting connection string
private static string executableLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
private static string oldconnectionstring = Path.Combine(executableLocation, "YourDB.db");
private static string connectionString = "Data Source =" + oldconnectionstring.ToString();
After getting connection, to add your input to database follow below steps
using (SQLiteConnection conn = new SQLiteConnection(connectionString))
{
//Open connection to DB
conn.Open();
//Query to be fired
string sql = "Your Query to insert rows";
//Executing the query
using (SQLiteCommand cmd = new SQLiteCommand(sql, conn))
{
//Executing the query
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
//Close connection to DB
conn.Close();
}
Hello i'm working on an android game project in unity3d 5 (language c#)that needs to save some data to sqlite database.
the game doesn't have a lot of data to store it has only 1 table .there are some plugins for unity that connect to sqlite but i don't want to use them .
so how can i store my data on sqlite file in unity ?
You can find your answer here
Create new folder under Assets Folder Rename it Plugins .
Copy sqlite3.def and sqlite3.dll into Assets/Plugins in your unity project .You can download these files here
http://www.sqlite.org/download.html for windows (Precompiled Binaries
for Windows)
Download SQLite Browser http://sourceforge.net/projects/sqlitebrowser/ or
http://sqliteadmin.orbmu2k.de/ download SQLite Administrator tool
Create Database in Assets folder in your unity project using SQLite Browser.
Copy System.Data.dll and Mono.Data.Sqlite.dll from **C:\Program Files (x86)\Unity \Editor\Data\Mono\lib\mono\2.0* and paste them in your Assets/Plugins* folder in your unity project.
Add these namespaces using Mono.Data.Sqlite; using System.Data; using System;
string conn= "URI=file:" + Application.dataPath + "/PickAndPlaceDatabase.s3db";
Replace PickAndPlaceDatabase.s3db with your database name
void Start () {
string conn = "URI=file:" + Application.dataPath + "/PickAndPlaceDatabase.s3db"; //Path to database.
IDbConnection dbconn;
dbconn = (IDbConnection) new SqliteConnection(conn);
dbconn.Open(); //Open connection to the database.
IDbCommand dbcmd = dbconn.CreateCommand();
string sqlQuery = "SELECT value,name, randomSequence " + "FROM PlaceSequence";
dbcmd.CommandText = sqlQuery;
IDataReader reader = dbcmd.ExecuteReader();
while (reader.Read())
{
int value = reader.GetInt32(0);
string name = reader.GetString(1);
int rand = reader.GetInt32(2);
Debug.Log( "value= "+value+" name ="+name+" random ="+ rand);
}
reader.Close();
reader = null;
dbcmd.Dispose();
dbcmd = null;
dbconn.Close();
dbconn = null;
}
Further SQLite Help Visit : http://www.tutorialspoint.com/sqlite/
I have a mssql database on remote machine and backup file for this database. I want to create a method (c#) for restoring of database from backup. I will execute my method on my local machine. Can somebody help me to create such method for restoring remote database?
Try the this:
public void RestoreDatabase(string fileName)
{
try
{
using (SqlConnection conn = new SqlConnection("connectionString"))
{
string sql = "RESTORE DATABASE YourDatabase FROM DISK = N''" + fileName;
conn.Open();
SqlCommand _command = new SqlCommand(sql, conn);
_command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
throw;
}
}
You call it this way :
RestoreDatabase(#"\\remotemachine\...\YourFile.bak");
NB: Put an actual path for where the file is located
As I can read from SQLite FAQ it supports multiple processes reading (SELECT) and only one process writing (INSERT, UPDATE, DELETE) database at any moment in time:
SQLite uses reader/writer locks to control access to the database.
When any process wants to write, it must lock the entire database file
for the duration of its update. But that normally only takes a few
milliseconds. Other processes just wait on the writer to finish then
continue about their business
I'm using System.Data.SQLite adapter via c#.
Could someone expalin me plz, how exactly this process is going on?
Will this process work automatically and writing SQLiteCommand will simply wait if there is another writing SQLiteCommand already executing over the same database?
Or maybe it will throw an exception? What kind of it?
Sorry but I found no information about this mechanics :)
Thank you.
UPDATE:
I've found post saying that exception will be raised with a specific errorcode
Is that statement correct?
I've investigated it by myself:
I created a sample SQLite database c:\123.db with one table Categories containing two fields: ID (uniqueidentifier) and Name (nvarchar).
I then wrote some multi-thread code to emulate multiple write access to the database (don't forget to add a System.Data.SQLite reference to your project if you use this code):
using System;
using System.Data.SQLite;
using System.Threading.Tasks;
namespace SQLiteTest
{
class Program
{
static void Main(string[] args)
{
var tasks = new Task[100];
for (int i = 0; i < 100; i++)
{
tasks[i] = new Task(new Program().WriteToDB);
tasks[i].Start();
}
foreach (var task in tasks)
task.Wait();
}
public void WriteToDB()
{
try
{
using (SQLiteConnection myconnection = new SQLiteConnection(#"Data Source=c:\123.db"))
{
myconnection.Open();
using (SQLiteTransaction mytransaction = myconnection.BeginTransaction())
{
using (SQLiteCommand mycommand = new SQLiteCommand(myconnection))
{
Guid id = Guid.NewGuid();
mycommand.CommandText = "INSERT INTO Categories(ID, Name) VALUES ('" + id.ToString() + "', '111')";
mycommand.ExecuteNonQuery();
mycommand.CommandText = "UPDATE Categories SET Name='222' WHERE ID='" + id.ToString() + "'";
mycommand.ExecuteNonQuery();
mycommand.CommandText = "DELETE FROM Categories WHERE ID='" + id.ToString() + "'";
mycommand.ExecuteNonQuery();
}
mytransaction.Commit();
}
}
}
catch (SQLiteException ex)
{
if (ex.ReturnCode == SQLiteErrorCode.Busy)
Console.WriteLine("Database is locked by another process!");
}
}
}
}
The result on my Core2Duo E7500 is that Exception is never raised!
Looks like SQLite is optimised enough for my needs (locking/unlocking is really fast and normally only takes a few milliseconds as SQLite FAQ tells us) - Great!
Note that there is no need to retrieve an integer ErrorCode for an SQLiteException - you can use a special enum ReturnCode field instead. All codes are described here.
Hope this information will help somebody.