Flyway 4.0.3 to 8.4.1 upgrade issue - flyway

Using the SqlMigrationExecutor instance I was executing SQL scripts present in the location folder.
I am trying to upgrade flyway version to 8.4.1 but couldn't able to create SqlMigrationExecutor and perform Sql scripts execution.
Can someone please assist in translating the below code that was developed using Flyway 4.0.3?
Flyway.execute(new Command<Void>() {
#Override
public Void execute(final Connection connectionMetaDataTable, final Connection connectionUserObjects,
final MigrationResolver migrationResolver, final MetaDataTable metaDataTable,
final DbSupport dbSupport, final Schema[] schemas, final FlywayCallback[] flywayCallbacks) {
LOG.info(" Executing " + location);
final MigrationExecutor migrationExecutor = new SqlMigrationExecutor(dbSupport, sqlScriptResource, placeholderReplacer, getEncoding());
if (migrationExecutor.executeInTransaction()) {
new TransactionTemplate(connectionUserObjects).execute(new TransactionCallback<Void>() {
#Override
public Void doInTransaction() throws SQLException {
migrationExecutor.execute(connectionUserObjects);
return null;
}
});
}
}
}

Related

Entity Framework tables are not generated using in memory SQLite

We are trying to move to using an in-memory SQLite instance for our unit test automation, instead of SQL Server or SQL Express. We use Entity Framework Core.
I think I have everything configured correctly, but it's still failing, so I must be missing a step, but I'm not sure what it is.
In our test project's app.config, I've specified:
<connectionStrings>
<add name="BusinessDb" providerName="System.Data.SQLite.EF6" connectionString="data source=:memory:"/>
</connectionStrings>
Our production concrete class is a bit more complex (it has many more modelBuilder calls in the OnModelCreating() method and many more DbSet objects, but it is basically like this:
namespace Business.Base.Concrete
{
public class SqlBusinessDb
: DbContext
, IBusinessDb
{
public string ConnectionString { get; set; }
public SqlBusinessDb(string connectionString)
{
ConnectionString = connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
if (ConnectionString.Contains("memory"))
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlite(ConnectionString,
options =>
options.CommandTimeout(SqlSettings.s_CommandTimeoutInSec.CurrentValue)
.MigrationsHistoryTable("_BusinessDB_Migrations"))
.AddInterceptors(new Deals.Base.SQL.SqlPerfCounterInterceptor());
}
else
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(ConnectionString,
options =>
options.CommandTimeout(SqlSettings.s_CommandTimeoutInSec.CurrentValue)
.MigrationsHistoryTable("_BusinessDB_Migrations")
.EnableRetryOnFailure())
.AddInterceptors(new Deals.Base.SQL.SqlPerfCounterInterceptor());
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Has<BillingPlan>()
.HasManyToOne(p => p.Companies, a => a.BillingPlan, a => a.BillingPlan_Id)
}
public int ExecuteStoreCommand(string commandText, params object[] parameters)
{
return Database.ExecuteSqlRaw(commandText, parameters);
}
public DbSet<Features.FeatureOverride_Plan> FeaturesPlan { get; set; }
public DbSet<Business> Businesses { get; set; }
}
}
In our test project we call it like so:
public static TestBusinessDb GetInstance()
{
SqlBusinessDb realRepository = new SqlBusinessDb();
if (!_hasBeenMigrated)
{
_hasBeenMigrated = true;
DatabaseFacade dbf = realRepository.Database;
var issqlite = dbf.IsSqlite();
var tables = dbf.ExecuteSqlRaw("SELECT * FROM information_schema.tables;");
// for the Test Repository, we migrate once when we first try and connect.
realRepository.Database.Migrate();
}
}
This code fails on the "dbf.ExecuteSqlRaw()" line with:
Microsoft.Data.Sqlite.SqliteException : SQLite Error 1: 'no such table: information_schema.tables'.
If I remove that line, it fails on: realRepository.Database.Migrate(); with
Microsoft.Data.Sqlite.SqliteException : SQLite Error 1: 'no such table: _BusinessDB_Migrations'.
When debugging it successfully ran the OnConfiguring and OnModelCreating methods and I watched it execute a SQL command that created that table. dbf.ProviderName returns "Microsoft.EntityFrameworkCore.Sqlite". So, why aren't the tables being found? Is there something else that needs to be in place that I'm missing?
It turns out that SQLite is unable to handle migrations anyway, so it is not a viable option.

SQLITE Delete item does't delete for real

I got a xamarin forms app, and the problem is when I delete an item from a sqlite table, it looks like all works, the item is deleted from the collection, the grids got updated, etc, but when I restart the app, the item is still there. its like the delete only works in memory but it never got saved in the database.
my code is below
I create an instance called DB in my App constructor
public partial class App
{
static Database database;
public static Database DB
{
get
{
if (database == null)
{
string nombreBD = "MyDataBaseFile.db3";
string _databasePath = Path.Combine(Xamarin.Essentials.FileSystem.AppDataDirectory, nombreBD);
database = new Database(_databasePath);
}
return database;
}
}
................
}
I'm using sqlite with tables created from classes, like this
db = new SQLiteAsyncConnection(dbPath);
db.CreateTableAsync<MyType>().Wait();
where MyType is a class like this
public class MyType
{
[PrimaryKey]
public int Idtable { get; set; }
......
}
I try to delete a row of the table like this:
var x = await App.DB.GetItemAsync<MyType>(obj.Idtable );
int regsDeleted = await App.DB.DeleteItemAsync<MyType>(x);
the GetItemsAsync is basically: await db.FindAsync<T>(id);
public async Task<T> GetItemAsync<T>(int id) where T : new()
{
try
{
return await db.FindAsync<T>(id);
}
catch (System.Exception ex)
{
throw new System.Exception($"Error sqlLite {MethodBase.GetCurrentMethod().Name}: {ex.Message}");
}
}
and the delete method is this:
public async Task<int> DeleteItemAsync<T>(T item) where T : new()
{
try
{
int regsDeleted=await db.DeleteAsync(item);
db.GetConnection().Commit();
return regsDeleted;
}
catch (System.Exception ex)
{
throw new System.Exception($"Error sqlLite {MethodBase.GetCurrentMethod().Name}: {ex.Message}");
}
}
like I said I got no errors and all looks like worked, but when restart the app, the item still there!!
any Idea? something to add in the connection maybe? transactions?... any help will be great
thanks
UPDATE After a lot of test I realize the problem is not the delete. The problem is that every time I run the app from VS to my android device through USB cable, I don't know how or why the database get restored from some backup, that I donĀ“t know when or where was done. Looks like Android have a backup and the "data" of my app and when a new version comes he just restore the data. I read somne that said the Xamarin.Essentials.FileSystem.AppDataDirectory should not be used to save databases, so the question is. where is th right place to save the SQLLite database.Any Idea? My app don't deployed an empty database, my app create the database in the first execution. Does anyone knows how to avoid that restauration of the folder? every time I run the app from VisualStudio ?
The DeleteAsync works without Commit. I make come changes for your code. It works on my side.
I add the PrimaryKey and AutoIncrement attributes to ensure that each Note instance in the SQLite.NET database will have a unique id provided by SQLite.NET.
public class MyType
{
[PrimaryKey, AutoIncrement]
public int Idtable { get; set; }
public string Text { get; set; }
}
The code for the connect to the database, save the record, delete the row and get the all the items.
readonly string _databasePath = Path.Combine(Xamarin.Essentials.FileSystem.AppDataDirectory, "MyDataBaseFile.db3");
SQLiteAsyncConnection database;
public MyType myType { get; set; }
int i = 0;
public Page2()
{
InitializeComponent();
}
private void Connect_Clicked(object sender, EventArgs e)
{
database = new SQLiteAsyncConnection(_databasePath);
database.CreateTableAsync<MyType>().Wait();
}
async void Save_Clicked(object sender, EventArgs e)
{
myType = new MyType() { Text = "Hello" + i };
if (myType.Idtable != 0)
{
// Update an existing note.
await database.UpdateAsync(myType);
i++;
}
else
{
// Save a new note.
await database.InsertAsync(myType);
i++;
}
}
async void Delete_Clicked(object sender, EventArgs e)
{
var x = await database.FindAsync<MyType>(myType.Idtable);
int regsDeleted = await database.DeleteAsync(x);
}
async void Get_Clicked(object sender, EventArgs e)
{
var s = await database.Table<MyType>().ToListAsync();
try
{
var s2 = await database.FindAsync<MyType>(myType.Idtable);
}
catch
{
return;
}
}
}
Please note if i restart the app, there is no myType.Idtable. So i use the try catch to make my project run.
Add four items for the database and detele the last one.
After restart the app, the items:
I had a similar error. Very annoying and couldn't figure it out. After reading this question I have just deleted the db3 file on the android device rerun my app and now it works. I suspect that during development and changing the structure of the class for the table something gets screwed up. Deleting the database db3 (or whatever, sqlite doesn't care) re-created the the tables completely.
So how do you get to the file? (For a Pixel 5 emulator)
I used Android Studio and the DeviceFileExplorer (View>ToolWindows)
But where is it. Well In my app I use
private readonly static string filename = "xxx.db3";
...
database = new Database.Database(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), filename));
and I (eventually) found this located in data>data>(my Application Id)>files
where my ApplicationID is something like uk.co.mydomainname.myappname
I just then deleted the file with a right click delete
(Note: I found sometimes you have to right click the files folder and synchronise to refresh the tree and see the db file)
Hope this helps.
PS I wish for me (.net maui) the documentation explained more clearly the paths and where things get located/placed!!

How to upgrade from flyway 3 directly to flyway 5

Working on a product that is deployed by many clients in many production environments. It includes at least one Spring Boot app.
We've used flyway for db schema migrations. Upgrading from Spring Boot 1.5.x to 2.0.x has bumped our flyway version from 3.x to 5.x.
The Spring Boot migration guide simply says to upgrade to flyway 4 before the boot upgrade. However, this would require all of our customers to do an intermediate upgrade before being able to upgrade to the latest.
So, the question is: How would you upgrade from flyway 3 directly to flyway 5?
Step 0.
Upgrade to spring boot v2.1 (and therby implicitly to flyway 5).
Step 1.
Since schema_version was used in flyway 3.x let new flyway versions know that they should keep using this table.:
# application.yml
spring.flyway.table: schema_version # prior flyway version used this table and we keep it
Step 2.
Create file src/main/ressources/db/migration/flyway_upgradeMetaDataTable_V3_to_V4.sql for upgrading the meta table based on the dialect you use.
See https://github.com/flyway/flyway/commit/cea8526d7d0a9b0ec35bffa5cb43ae08ea5849e4#diff-b9cb194749ffef15acc9969b90488d98 for the update scripts of several dialects.
Here is the one for postgres and assuming the flyway table name is schema_version:
-- src/main/ressources/db/migration/flyway_upgradeMetaDataTable_V3_to_V4.sql
DROP INDEX "schema_version_vr_idx";
DROP INDEX "schema_version_ir_idx";
ALTER TABLE "schema_version" DROP COLUMN "version_rank";
ALTER TABLE "schema_version" DROP CONSTRAINT "schema_version_pk";
ALTER TABLE "schema_version" ALTER COLUMN "version" DROP NOT NULL;
ALTER TABLE "schema_version" ADD CONSTRAINT "schema_version_pk" PRIMARY KEY ("installed_rank");
UPDATE "schema_version" SET "type"='BASELINE' WHERE "type"='INIT';
Step 3.
Create Java file your.package/FlywayUpdate3To4Callback.java
Please note that this does the following:
Run the sql script from Step 2
call Flyway.repair()
// FlywayUpdate3To4Callback.java
package your.package;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.callback.Callback;
import org.flywaydb.core.api.callback.Context;
import org.flywaydb.core.api.callback.Event;
import org.flywaydb.core.api.configuration.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
#Component
#Order(HIGHEST_PRECEDENCE)
#Slf4j
public class FlywayUpdate3To4Callback implements Callback {
private final Flyway flyway;
public FlywayUpdate3To4Callback(#Lazy Flyway flyway) {
this.flyway = flyway;
}
private boolean checkColumnExists(Configuration flywayConfiguration) throws MetaDataAccessException {
return (boolean) JdbcUtils.extractDatabaseMetaData(flywayConfiguration.getDataSource(),
callback -> callback
.getColumns(null, null, flywayConfiguration.getTable(), "version_rank")
.next());
}
#Override
public boolean supports(Event event, Context context) {
return event == Event.BEFORE_VALIDATE;
}
#Override
public boolean canHandleInTransaction(Event event, Context context) {
return false;
}
#Override
public void handle(Event event, Context context) {
boolean versionRankColumnExists = false;
try {
versionRankColumnExists = checkColumnExists(context.getConfiguration());
} catch (MetaDataAccessException e) {
log.error("Cannot obtain flyway metadata");
return;
}
if (versionRankColumnExists) {
log.info("Upgrading metadata table the Flyway 4.0 format ...");
Resource resource = new ClassPathResource("db/migration/common/flyway_upgradeMetaDataTable_V3_to_V4.sql",
Thread.currentThread().getContextClassLoader());
ScriptUtils.executeSqlScript(context.getConnection(), resource);
log.info("Flyway metadata table updated successfully.");
// recalculate checksums
flyway.repair();
}
}
}
Step 4.
Run spring boot.
The log should show info messages similar to these:
...FlywayUpdate3To4Callback : Upgrading metadata table the Flyway 4.0 format
...FlywayUpdate3To4Callback : Flyway metadata table updated successfully.
Credits
This answer is based on Eduardo Rodrigues answer by changing:
Use Event.BEFORE_VALIDATE to trigger a flyway callback that upgrade flyway 3 to 4.
more information on application.yml setup
provide upgrade sql migration script
In case I'm not the last person on the planet to still be upgrading from 3 to 5.
Problem:
I wanted the upgrade to be transparent to other developers on the project as well as not requiring any special deployment instructions when upgrading on the live applications, so I did the following.
I had a look at how version 4 handled the upgrade:
In Flyway.java a call is made to MetaDataTableImpl.upgradeIfNecessary
upgradeIfNecessary checks if the version_rank column still exists, and if so runs a migration script called upgradeMetaDataTable.sql from org/flywaydb/core/internal/dbsupport/YOUR_DB/
If upgradeIfNecessary executed, then Flyway.java runs a DbRepair calling repairChecksumsAndDescriptions
This is easy enough to do manually but to make it transparent. The app is a spring app, but not a spring boot app, so at the time I had flyway running migrations automatically on application startup by having LocalContainerEntityManager bean construction dependent on the flyway bean, which would call migrate as its init method (explained here Flyway Spring JPA2 integration - possible to keep schema validation?), so the order of bootstrapping would be:
Flyway bean created -> Flyway migrate called -> LocalContainerEntityManager created
Solution:
I changed the order of bootstrapping to:
Flyway bean created -> Flyway3To4Migrator -> LocalContainerEntityManager created
where Flyway3To4Migrator would perform the schema_table changes if needed, run the repair if the upgrade happened, and then always run flyway.migrate to continue the migrations.
#Configuration
public class AppConfiguration {
#Bean
// Previously: #DependsOn("flyway")
#DependsOn("flyway3To4Migrator")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
...
}
// Previously: #Bean(initMethod = "migrate")
#Bean
public Flyway flyway(DataSource dataSource) {
...
}
}
#Component
#DependsOn("flyway")
public class Flyway3To4Migrator {
private final Log logger = LogFactory.getLog(getClass());
private Flyway flyway;
#Autowired
public Flyway3To4Migrator(Flyway flyway) {
this.flyway = flyway;
}
#PostConstruct
public void migrate() throws SQLException, MetaDataAccessException {
DataSource dataSource = flyway.getDataSource();
boolean versionRankColumnExists = checkColumnExists(dataSource);
if (versionRankColumnExists) {
logger.info("Upgrading metadata table to the Flyway 4.0 format ...");
Resource resource = new ClassPathResource("upgradeMetaDataTable.sql", getClass().getClassLoader());
ScriptUtils.executeSqlScript(dataSource.getConnection(), resource);
logger.info("Metadata table successfully upgraded to the Flyway 4.0 format.");
logger.info("Running flyway:repair for Flyway upgrade.");
flyway.repair();
logger.info("Complete flyway:repair.");
}
logger.info("Continuing with normal Flyway migration.");
flyway.migrate();
}
private boolean checkColumnExists(DataSource dataSource) throws MetaDataAccessException {
return (Boolean) JdbcUtils.extractDatabaseMetaData(
dataSource, dbmd -> {
ResultSet rs = dbmd.getColumns(
null, null,
"schema_version",
"version_rank");
return rs.next();
});
}
}
A few things to note:
At some point we will remove the extra Flyway3To4Migrator class and revert the configuration to the way it was.
I copied the relevant upgradeMetaDataTable.sql file for my database from the v4 Flyway jar and simplified it to my table names etc. You could grab the schema and table names from flyway if you needed to.
there is no transaction management around the SQL script, you might want to add that
Flyway3To4Migrator calls flyway.repair(), which does a little more than DbRepair.repairChecksumsAndDescriptions(), but we were happy to accept the database must be in a good state before its run
If you're using Spring Boot, you can register a callback that does the upgrade on beforeMigrate(). The code is similar to #trf and looks like this:
#Component
#Order(HIGHEST_PRECEDENCE)
#Slf4j
public class FlywayUpdate3To4Callback extends BaseFlywayCallback {
private final Flyway flyway;
public FlywayUpdate3To4Callback(#Lazy Flyway flyway) {
this.flyway = flyway;
}
#Override
public void beforeMigrate(Connection connection) {
boolean versionRankColumnExists = false;
try {
versionRankColumnExists = checkColumnExists(flywayConfiguration);
} catch (MetaDataAccessException e) {
log.error("Cannot obtain flyway metadata");
return;
}
if (versionRankColumnExists) {
log.info("Upgrading metadata table the Flyway 4.0 format ...");
Resource resource = new ClassPathResource("upgradeMetaDataTable.sql",
Thread.currentThread().getContextClassLoader());
ScriptUtils.executeSqlScript(connection, resource);
log.info("Flyway metadata table updated successfully.");
// recalculate checksums
flyway.repair();
}
}
private boolean checkColumnExists(FlywayConfiguration flywayConfiguration) throws MetaDataAccessException {
return (boolean) JdbcUtils.extractDatabaseMetaData(flywayConfiguration.getDataSource(),
callback -> callback
.getColumns(null, null, flywayConfiguration.getTable(), "version_rank")
.next());
}
Notice that you don't need to manually call flyway.migrate() here.
The code above is not compatible with version 5. It uses deprecated classes.
Here is an updated version.
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.callback.Callback;
import org.flywaydb.core.api.callback.Context;
import org.flywaydb.core.api.callback.Event;
import org.flywaydb.core.api.configuration.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.stereotype.Component;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
#Component
#Order(HIGHEST_PRECEDENCE)
#Slf4j
public class FlywayUpdate3To4Callback implements Callback {
private final Flyway flyway;
public FlywayUpdate3To4Callback(#Lazy Flyway flyway) {
this.flyway = flyway;
}
private boolean checkColumnExists(Configuration flywayConfiguration) throws MetaDataAccessException {
return (boolean) JdbcUtils.extractDatabaseMetaData(flywayConfiguration.getDataSource(),
callback -> callback
.getColumns(null, null, flywayConfiguration.getTable(), "version_rank")
.next());
}
#Override
public boolean supports(Event event, Context context) {
return event == Event.BEFORE_VALIDATE;
}
#Override
public boolean canHandleInTransaction(Event event, Context context) {
return false;
}
#Override
public void handle(Event event, Context context) {
boolean versionRankColumnExists = false;
try {
versionRankColumnExists = checkColumnExists(context.getConfiguration());
} catch (MetaDataAccessException e) {
log.error("Cannot obtain flyway metadata");
return;
}
if (versionRankColumnExists) {
log.info("Upgrading metadata table the Flyway 4.0 format ...");
Resource resource = new ClassPathResource("db/migration/flyway_upgradeMetaDataTable_V3_to_V4.sql",
Thread.currentThread().getContextClassLoader());
ScriptUtils.executeSqlScript(context.getConnection(), resource);
log.info("Flyway metadata table updated successfully.");
// recalculate checksums
flyway.repair();
}
}
}
I tried to skip v4 too but didn't work. Running the repair from 3 to 5 will make the checksums correct, but won't change the schema_version format. That has changed as well.
It seems you need to go to v4 first. Even if temporarily just to run mvn flyway:validate, which will repair schema_version.
I've done this on this repo: https://github.com/fabiofalci/flyway-from-3-to-5/commits/5.0.7
The first commit is v3, the second commit is v4 (where I ran validate) and then the third commit on v5 the schema is correct.
It worked for me, except I had to put Event.BEFORE_VALIDATE again instead of Event.BEFORE_MIGRATE that was present in the last version of the FlywayUpdate3To4Callback Class. This is because I had a checksum not valid on a migration already run, so it needed to be fixed before validating and not before migrating. Thanks.

How to get job's information (name, status, last run, etc) in SQL Server agent using c# and mvc?

I am a rookie with ASP.NET currently developing monitoring system for SQL Server, and still working on retrieving job's information so I can show them on the page.
I tried to use Mr. Alexey Zimarev's code this code
And I wrote it on my controller like this
public class JobsController : Controller
{
static readonly string SqlServer = #"DESKTOP-PQD9KKN";
private ApplicationDbContext _context;
public JobsController()
{
_context = new ApplicationDbContext();
}
protected override void Dispose(bool disposing)
{
_context.Dispose();
}
[Route("Customers/MigrateJob")]
public ActionResult MigrateJob()
{
ServerConnection conn = new ServerConnection(SqlServer);
Server server = new Server(conn);
JobCollection jobs = server.JobServer.Jobs;
foreach(Job job in jobs)
{
var jobactivity = new JobActivity
{
Name = job.Name,
IsEnabled = job.IsEnabled
....so on
};
_context.JobActivities.Add(jobactivity);
}
return RedirectToAction("List", "Jobs");
}
public ActionResult List()
{
var jobactivities = _context.JobActivities.ToList();
return View(jobactivities);
}
}
My approach is to store the job's information from SQL Server Agent to my JobActivity table using MigrateJob(). The problem is the job's information hasn't stored in my table yet without any error messages.
My Tools:
VS 2017
SQL Server ver 13
Any help would be appreciated :)

Windows Store Application Place SQLite File in LocalState Folder

I am building a Windows 8 application using sql-net and mvvmcross for data access to a sqlite database. This would be applicable to any Win-8 or Win-Phone app.
I need to install an existing sqlite file on app start.
When using the connection you use syntax such as this
public FlashCardManager(ISQLiteConnectionFactory factory, IMvxMessenger messenger)
{
_messenger = messenger;
_connection = factory.Create("Dictionary.sqlite");
_connection.CreateTable<FlashCardSet>();
_connection.CreateTable<FlashCard>();
}
public void CreateCard(FlashCard flashCard)
{
_connection.Insert(flashCard);
}
That connection creates a file in: C:\Users\USER\AppData\Local\Packages\793fd702-171e-474f-ab3b-d9067c58709b_ka9b83fa3fse2\LocalState
My application uses an existing sqlite database file that I have created. I need to place it in this folder when the application is installed. How would I go about doing this?
Thanks,
JH
Make sure you have the database file you want your app to start off with in one of your apps folders (as in the folders visible in visual studios solution explorer). For this example I'll call this folder "Assets"
All you need to do then is copy this file to the LocalState folder the first time your app runs. This can be done in App.xaml.cs
private async void InitializeAppEnvironment()
{
try
{
if (!(await AppHelper.ExistsInStorageFolder(AppHelper.localFolder, dbName)))
{
StorageFile defaultDb = await AppHelper.installedLocation.GetFileAsync("Assets\\" + dbName);
await defaultDb.CopyAsync(AppHelper.localFolder);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e);
}
}
I made an AppHelper class to simplify accessing the app data folders, here's the parts I used above:
static class AppHelper
{
public static StorageFolder installedLocation = Windows.ApplicationModel.Package.Current.InstalledLocation;
public static StorageFolder localFolder = ApplicationData.Current.LocalFolder;
public static async Task<bool> ExistsInStorageFolder(this StorageFolder folder, string fileName)
{
try
{
await folder.GetFileAsync(fileName);
return true;
}
catch (FileNotFoundException)
{
return false;
}
}
}
For a more detailed response on MVVM cross I found the current discussion about cross platform file placement in this discussion: Link
The current thought is that you have to inject platform specific code for this sort of functionality.

Resources