I'm deploying a winform application built with vs 2008 0n XP sp3.
I created a database with empty schema which i dropped in the root folder of the project and in properties i choosed Build Action: Embedded Resources and Copy to Output directory : Copy always. Now instead of having connectionstring in the app.config connectionString section, i put an entry in appSetting: key="database";value="mydb.db;Version=3".
So to create my connectionString i used :
SQLiteConnection con = new SQLiteConnection("Data Source=" + Path.Combine(Application.StartupPath, ConfigurationManager.AppSettings["database"]));
Everything works fine and i packaged the app with a setup project.Now after i installed the app the database could not be found and i was obliged to copy the database to the Application Folder in the setup project for it to work.
what i thought is that db is supposed to be in the app dll because of copy always .but i can't access it.So what exactly did i do wrong?
i'm suspecting i should have just connected to the root db meaning not using Application.StartupPath
But i'm here asking for the best practices cause what i did is working but still looking like workaround so please can anyone share his experience with me?
thanks for reading
Embedded Resource means the database gets embedded in your dll. The Copy to output directory setting doesn't apply in this case, that's used for Build Action: Content.
With the database embedded, you basically have to un-embed it on first use. To do this read it out of the Assembly and store it to a file.
class EmbeddedResourceTest
{
public static void Test()
{
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Test.db");
using(var resourceStream = typeof(EmbeddedResourceTest).Assembly.GetManifestResourceStream("Test.db"))
{
using(var fileStream = File.OpenWrite(path))
{
CopyStream(resourceStream, fileStream);
}
}
// now access database using 'path'
}
public static void CopyStream(Stream inputStream, Stream outputStream)
{
CopyStream(inputStream, outputStream, 4096);
}
public static void CopyStream(Stream inputStream, Stream outputStream, int bufferLength)
{
var buffer = new byte[bufferLength];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer, 0, bufferLength)) > 0)
{
outputStream.Write(buffer, 0, bytesRead);
}
}
}
Related
I have started using the Xamarin plugin for Visual Studio to create an Android app.
I have a local SQL database, and I want to call it to display data. I don't see how I can do this. Is it possible?
After thinking this was a trivial thing to do, I was proven wrong when I tried setup a quick test project. This post will contain a full tutorial on setting up a DB for an Android App in Xamarin that will come in handy as a reference for future Xamarin users.
At a glance:
Add Sqlite.cs to your project.
Add your database file as an Asset.
Set your database file to build as an AndroidAsset.
Manually copy the database file out of your apk to another directory.
Open a database connetion using Sqlite.SqliteConnection.
Operate on the database using Sqlite.
Setting up a local database for a Xamarin Android project
1. Add Sqlite.cs to your project.
Start by going to this repository and downloading Sqlite.cs; this provides the Sqlite API that you can use to run queries against your db. Add the file to your project as a source file.
2. Add DB as asset.
Next, get your DB and copy it into the Assets directory of your Android project and then import it into your project so that it appears beneath the Assets folder within your solution:
I'm using the Chinook_Sqlite.sqlite database sample renamed to db.sqlite from this site throughout this example.
3. Set DB to build as AndroidAsset.
Right click on the DB file and set it to build action AndroidAsset. This will ensure that it is included into the assets directory of the APK.
4. Manually copy DB out of your APK.
As the DB is included as an Asset (packaged within the APK) you will need to extract it out.
You can do this with the following code:
string dbName = "db.sqlite";
string dbPath = Path.Combine (Android.OS.Environment.ExternalStorageDirectory.ToString (), dbName);
// Check if your DB has already been extracted.
if (!File.Exists(dbPath))
{
using (BinaryReader br = new BinaryReader(Android.App.Application.Context.Assets.Open(dbName)))
{
using (BinaryWriter bw = new BinaryWriter(new FileStream(dbPath, FileMode.Create)))
{
byte[] buffer = new byte[2048];
int len = 0;
while ((len = br.Read(buffer, 0, buffer.Length)) > 0)
{
bw.Write (buffer, 0, len);
}
}
}
}
This extracts the DB as a binary file from the APK and places it into the system external storage path. Realistically the DB can go wherever you want, I've just chosen to stick it here.
I also read that Android has a databases folder that will store databases directly; I couldn't get it to work so I've just ran with this method of using an existing DB.
5. Open DB Connection.
Now open a connection to the DB through the Sqlite.SqliteConnection class:
using (var conn = new SQLite.SQLiteConnection(dbPath))
{
// Do stuff here...
}
6. Operate on DB.
Lastly, as Sqlite.net is an ORM, you can operate on the database using your own data types:
public class Album
{
[PrimaryKey, AutoIncrement]
public int AlbumId { get; set; }
public string Title { get; set; }
public int ArtistId { get; set; }
}
// Other code...
using (var conn = new SQLite.SQLiteConnection(dbPath))
{
var cmd = new SQLite.SQLiteCommand (conn);
cmd.CommandText = "select * from Album";
var r = cmd.ExecuteQuery<Album> ();
Console.Write (r);
}
Summary
And that's how to add an existing Sqlite database to your Xamarin solution for Android! For more information check out the examples included with the Sqlite.net library, its unit tests and the examples in the Xamarin documentation.
Here is the one that I'm using and it's working
install the Sqlite plugin
create interface to access different platforms services
create a model for the table
implement the interface that you created earlier on all of the
platform you want to use
use the plugin to create, get, insert, etc on your table
for more detailed information check this
I have following C# code in a console application.
Whenever I debug the application and run the query1 (which inserts a new value into the database) and then run query2 (which displays all the entries in the database), I can see the new entry I inserted clearly. However, when I close the application and check the table in the database (in Visual Studio), it is gone. I have no idea why it is not saving.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlServerCe;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
string fileName = "FlowerShop.sdf";
string fileLocation = "|DataDirectory|\\";
DatabaseAccess dbAccess = new DatabaseAccess();
dbAccess.Connect(fileName, fileLocation);
Console.WriteLine("Connected to the following database:\n"+fileLocation + fileName+"\n");
string query = "Insert into Products(Name, UnitPrice, UnitsInStock) values('NewItem', 500, 90)";
string res = dbAccess.ExecuteQuery(query);
Console.WriteLine(res);
string query2 = "Select * from Products";
string res2 = dbAccess.QueryData(query2);
Console.WriteLine(res2);
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e);
Console.ReadLine();
}
}
}
class DatabaseAccess
{
private SqlCeConnection _connection;
public void Connect(string fileName, string fileLocation)
{
Connect(#"Data Source=" + fileLocation + fileName);
}
public void Connect(string connectionString)
{
_connection = new SqlCeConnection(connectionString);
}
public string QueryData(string query)
{
_connection.Open();
using (SqlCeDataAdapter da = new SqlCeDataAdapter(query, _connection))
using (DataSet ds = new DataSet("Data Set"))
{
da.Fill(ds);
_connection.Close();
return ds.Tables[0].ToReadableString(); // a extension method I created
}
}
public string ExecuteQuery(string query)
{
_connection.Open();
using (SqlCeCommand c = new SqlCeCommand(query, _connection))
{
int r = c.ExecuteNonQuery();
_connection.Close();
return r.ToString();
}
}
}
EDIT: Forgot to mention that I am using SQL Server Compact Edition 4 and VS2012 Express.
It is a quite common problem. You use the |DataDirectory| substitution string. This means that, while debugging your app in the Visual Studio environment, the database used by your application is located in the subfolder BIN\DEBUG folder (or x86 variant) of your project. And this works well as you don't have any kind of error connecting to the database and making update operations.
But then, you exit the debug session and you look at your database through the Visual Studio Server Explorer (or any other suitable tool). This window has a different connection string (probably pointing to the copy of your database in the project folder). You search your tables and you don't see the changes.
Then the problem get worse. You restart VS to go hunting for the bug in your app, but you have your database file listed between your project files and the property Copy to Output directory is set to Copy Always. At this point Visual Studio obliges and copies the original database file from the project folder to the output folder (BIN\DEBUG) and thus your previous changes are lost.
Now, your application inserts/updates again the target table, you again can't find any error in your code and restart the loop again until you decide to post or search on StackOverflow.
You could stop this problem by clicking on the database file listed in your Solution Explorer and changing the property Copy To Output Directory to Copy If Newer or Never Copy. Also you could update your connectionstring in the Server Explorer to look at the working copy of your database or create a second connection. The first one still points to the database in the project folder while the second one points to the database in the BIN\DEBUG folder. In this way you could keep the original database ready for deployment purposes and schema changes, while, with the second connection you could look at the effective results of your coding efforts.
EDIT Special warning for MS-Access database users. The simple act of looking at your table changes the modified date of your database ALSO if you don't write or change anything. So the flag Copy if Newer kicks in and the database file is copied to the output directory. With Access better use Copy Never.
Committing changes / saving changes across debug sessions is a familiar topic in SQL CE forums. It is something that trips up quite a few people. I'll post links to source articles below, but I wanted to paste the answer that seems to get the best results to the most people:
You have several options to change this behavior. If your sdf file is part of the content of your project, this will affect how data is persisted. Remember that when you debug, all output of your project (including the sdf) if in the bin/debug folder.
You can decide not to include the sdf file as part of your project and manage the file location runtime.
If you are using "copy if newer", and project changes you make to the database will overwrite any runtime/debug changes.
If you are using "Do not copy", you will have to specify the location in code (as two levels above where your program is running).
If you have "Copy always", any changes made during runtime will always be overwritten
Answer Source
Here is a link to some further discussion and how to documentation.
I have a program that works correctly on my computer in Debug mode.
When my program start he create a Sqlite data base file if not exists.
This is ok on my computer.
I create a setup version for production version. The program setup is ok.
But when I start the program (.exe) my db file is not created.
This is the connection string I used :
static string dbDirectopry = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
static string dbName = "MySqliteDb.db";
static string Connexion = Path.Combine(dbDirectopry, #"MySociety\MyApplication\" + dbName);
Hi thanks for your help,
this is the code that create db.
public static void CreateDb(string path)
{
SqLiteHelper sqlite = new SqLiteHelper(path);
try
{
User.CreateTable();
}
catch (Exception e)
{
throw e;
}
}
Normaly if the file doesn't exists he is automaticaly created.
If I try my application in Debug mode with Visual Studio my db is created and I can write into.
But when I deploy my application it doesn't work anymore.
My problem is is there any special directory (for windows) to create de db file?
i have created the data base in windows phone 7 and it works me fine
after rebuild the application it says that
The database file cannot be found. Check the path to the database. [ Data Source = \Applications\Data\6157CB94-31D3-4E6F-BFC3-78BE1549C10A\Data\IsolatedStore\amit.sdf ]
my code for db string is
` private const string Con_String = #"isostore:/amit.sdf";`
how to solve this pls give me any suggestion to solve this problem
Have you checked this sample How to create a basic local database app for Windows Phone?
they use this path for create the db
//Specify the connection string as a static, used in main page and app.xaml.
public static string DBConnectionString = "Data Source=isostore:/ToDo.sdf";
and also don't forget to check if the db exists
//Create the database if it does not exist.
using (ToDoDataContext db = new ToDoDataContext(ToDoDataContext.DBConnectionString))
{
if (db.DatabaseExists() == false)
{
//Create the database
db.CreateDatabase();
}
}
I put my database field in "assets" folder. And use the code from this blog to copy the database to "/data/data/my_packname/databases/", (This copy code i run it in the onCreate() method when i run this app) then use select * from ... to get data. But it gives me the exception: no such table.
Someone told me that if i am attempting to copy the file in SQLiteOpenHelper's onCreate(), it's too late. So the copy file code can not copy the complete file.
So i need to use adb or ddms to pull the database first?
So, Anyone can teach me how to use my own databse?
Can you tell me the setup?
I've used the instructions in that blog post and found them, while on the right track, to severely complicate the issue by unnecessarily extending SQLiteOpenHelper. I've had much better luck doing the following:
Create a utility class that creates the static db by copying it into the correct directory from assets, but doesn't get itself so hung up on following the SQLiteOpenHelper format.
Using the same utility class to open the db by using SQLiteDatabase.openDatabase()
Edit: Here is a version of this utility class I've created; it's not quite complete, but you'll get the drift.
public class DbUtils {
private static final String DB_PATH = "/data/data/com.mypackage.myapp/databases/";
private static final String DB_NAME = "my.db";
public static void createDatabaseIfNotExists(Context context) throws IOException {
boolean createDb = false;
File dbDir = new File(DB_PATH);
File dbFile = new File(DB_PATH + DB_NAME);
if (!dbDir.exists()) {
dbDir.mkdir();
createDb = true;
}
else if (!dbFile.exists()) {
createDb = true;
}
else {
// Check that we have the latest version of the db
boolean doUpgrade = false;
// Insert your own logic here on whether to upgrade the db; I personally
// just store the db version # in a text file, but you can do whatever
// you want. I've tried MD5 hashing the db before, but that takes a while.
// If we are doing an upgrade, basically we just delete the db then
// flip the switch to create a new one
if (doUpgrade) {
dbFile.delete();
createDb = true;
}
}
if (createDb) {
// Open your local db as the input stream
InputStream myInput = context.getAssets().open(DB_NAME);
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(dbFile);
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
}
public static SQLiteDatabase getStaticDb() {
return SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
}
}
After you've copied the database, you should try closing and reopening the SQLiteDatabase object before executing any query on it. I had a similar problem with copying a db from an input stream and that's what solved it for me.
here is my Version from "Silvio Donnini" Code :),
now you can update the Database easily.
private static final String DB_PATH = "/data/data/pakagename/databases/";
private static final String DB_NAME = "databaseName";
private static SQLiteDatabase db;
public static void createDatabaseIfNotExists(Context context,int version) throws IOException {
boolean createDb = false;
File dbDir = new File(DB_PATH);
File dbFile = new File(DB_PATH + DB_NAME);
if (!dbDir.exists()) {
dbDir.mkdir();
createDb = true;
}
else if (!dbFile.exists()) {
createDb = true;
}
else {
// Check that we have the latest version of the db
db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
if (db.getVersion() != version) {
dbFile.delete();
createDb = true;
}
}
if (createDb) {
// Open your local db as the input stream
InputStream myInput = context.getResources().openRawResource(R.raw.database);
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(dbFile);
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
SQLiteDatabase dbwrite = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READWRITE);
dbwrite.setVersion(version);
dbwrite.close();
if (db != null)
db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
}
}
public static SQLiteDatabase getStaticDb() {
if (db != null)
return db;
return SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
}
I know this is an old question, but I lost a lot of time figuring it out, with the help of all the replies.
The issue is that a device stores a database in his data/data/.../databases folder. So, when you change sth about the database (name, add android metadata table, size..) it wont make any difference because of the stored database and the method that checked for existing database.
To get the newest database, after changing it, you must run the program without checking for existing databses (e.g. instead of dbExist = checkDataBase(); make it just false).
dbExist = checkDataBase();
Change to:
dbExists = false;
After you picked up the "new" databse you can return to checking the existing ones.
Hope it helps someone,
dina
I know this is an old post, but for those who still get here after a Google or a Bing search, this is the solution to the stated problem:
in createDataBase() there is the following check;
this.getReadableDatabase();
This checks if there is already a database with the provided name and if not creates an empty database such that it can be overwritten with the one in the assets folder. On newer devices this works flawlessly but there are some devices on which this doesn't work. Mainly older devices. I do not know exactly why, but it seems like the getReadableDatabase() function not only gets the database but also opens it. If you then copy the database from the assets folder over it, it still has the pointer to an empty database and you will get table does not exist errors.
So in order to make it work on all devices you should modify it to the following lines:
SQLiteDatabase db = this.getReadableDatabase();
if (db.isOpen()){
db.close();
}
Even if the database is opened in the check, it is closed thereafter and it will not give you any more trouble.
Calm down guys,After long research finally found silly mistake for "no such table" error
Check name of database in Assets folder if it's like "DATABASE_NAME.EXTENSION" then put full name in Helper class with extension its solved my problem.
like say in Assets name of database is login.sqlite or login.db anything. put DB_NAME=login.sqlite fully with extention.
this tutorial now works perfectly.
The way of creating database from article you've posted is slightly diffrent from that how it's done in android examples (I don't want to say if it's good or bad).
I've learned how to use databases from SDKs NotePad sample
It's good example to start from, becouse it covers both database creation topic and database access through ContentProvider (it's really the only good way to get data from db, otherwise you will have problems when trying to get data simultaneusly from many places of your code).
You should note that SQLiteOpenHelper is really powerful and "it will help you" if you will use it properly. For example it stores current database version (not sqlite version but number you assingn with database schema version) and when you create new application version with new database structure you can update current schema to the new version in onUpdate.