How to open BerkleyDB file with multiple databases? - berkeley-db

I'm trying to read data from BerkeleyDB with multiple database inside. If I open it as in the source code below only the first DB is accessed. How to get access to the others?
using System;
using BerkeleyDB;
namespace WalletParser
{
public static class Program
{
static void Main(string[] args)
{
Database db = Database.Open(#"foo.db", new DatabaseConfig{ReadOnly = true});
Console.WriteLine(db.HasMultiple);
}
}
}

There is another Database.Open overload that gets database name as a parameter:
static Database Open(string Filename, string DatabaseName, DatabaseConfig cfg)

Related

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!!

Seeding variable data using EF Core 2.2

In all the examples and articles I've seen about seeding data using EF Core all of the data is hard-coded. I have a need to seed some data where part of it is variable. My model is:
public class Customer
{
[Key]
public Guid Id { get; set; }
public string ApiKey { get; set; }
}
Specifically, I want the ApiKey to contain a different value each time the seed operation runs. That way I get a different value for each environment (development, QA, production).
I created a method to generate a unique value and added the following to my OnModelCreating method.
modelBuilder.Entity<Customer>().HasData(new Customer
{
Id = Guid.NewGuid(),
ApiKey = GenerateApiKey()
});
The problem, as you have probably guessed, is that the call to GenerateApiKey happens when the migration is created so the value generated by GenerateApiKey is effectively hard-coded into the InsertData call.
migrationBuilder.InsertData(
table: "Customers",
columns: new[] { "Id", "ApiKey" },
values: new object[]
{
new Guid("bcde0c82-ad26-47fb-bd5f-1ad552d2b8f0"),
"56+hhUTjPwz0FM9uwYg19M5rfq6aUgmNde15Frn6TFY="
});
In EF 6.x I accomplished this using the Seed method of my DbMigrationsConfiguration subclass.
I realize I could modify the migration, but we're at a stage of development where we are dropping and recreating the database during changes and that would require every developer remember to do that when they regenerate the initial migration. I'd rather make it a little more foolproof than that.
You could always run a seed method once your host is ready like so (this is how I do it in 2.1):
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Seed().Run();
}
...
public static class WebHostExtensions
{
public static IWebHost Seed(this IWebHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var loggerFactory = services.GetRequiredService<ILoggerFactory>();
var context = services.GetRequiredService<MsbContext>();
// do whatever you need here with your data before migrations
...
context.Database.Migrate();
// do whatever you need here with your data after migrations
...
}
}
}

Uploading a file to a webservice without saving to server, database, or locally

I am creating a web service that will let the user upload a file and then I will make some changes to the file and return the file. But I want to get that file content without saving it to the server, database, or locally. Instead I want to save the content into a stream or something similar so that I can then run modifications on its content and return the new file.
I have tried doing the following but can only figure out how to get it to upload and save locally. Currently the file information is collected from the form data and the file headers.
namespace FileConverter.Controllers
{
[RoutePrefix("api/test")]
public class FileUploadController : ApiController
{
private static readonly string ServerUploadFolder = "C:\\Temp"; //Path.GetTempPath();
[Route("files")]
[HttpPost]
[ValidateMimeMultipartContentFilter]
public async Task<FileResult> UploadSingleFile()
{
var streamProvider = new MultipartFormDataStreamProvider(ServerUploadFolder);
await Request.Content.ReadAsMultipartAsync(streamProvider);
return new FileResult
{
FileNames = streamProvider.FileData.Select(entry => entry.LocalFileName),
Names = streamProvider.FileData.Select(entry => entry.Headers.ContentDisposition.FileName),
ContentTypes = streamProvider.FileData.Select(entry => entry.Headers.ContentType.MediaType),
};
}
}
}
I use a ValidateMimeMultipartContentFilter attribute to check if the correct MIME type is sent.
namespace FileConverter.Controllers
{
public class ValidateMimeMultipartContentFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
}
}
}
I then have a model set up to store some data.
namespace FileConverter.Controllers
{
public class FileResult
{
public IEnumerable<string> FileNames { get; set; }
public IEnumerable<string> ContentTypes { get; set; }
public IEnumerable<string> Names { get; set; }
}
}
Is there any way I can get the content of the file in a Stream/byte[] without saving the file locally and then reading its content? If so how would I go about doing that?
By the time your form action is invoked, ASP.NET has already done a lot of magic to interpret the file upload, so you can't really do much within the action itself. However, you can capture the byte streams in multipart forms as they come across the wire using an HttpModule or HttpHandler.
This example seems like it would be a good starting point.
I don't know whether an HttpRequest can begin returning data until after the payload has been received, so this is likely going to require some crazy cross-request magic if you literally want to "stream" the filtering process. On the other hand, if you were intending to keep the whole file in memory while you process it and then send it back afterward, I'd argue that you're better off allowing MVC to save the file as a temp file: you'd potentially get worse performance by keeping the entire uploaded file in memory while it's being uploaded.

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.

Fluent NHibernate SchemaExport to SQLite not pluralizing Table Names

I am using SQLite as my db during development, and I want to postpone actually creating a final database until my domains are fully mapped. So I have this in my Global.asax.cs file:
private void InitializeNHibernateSession()
{
Configuration cfg = NHibernateSession.Init(
webSessionStorage,
new [] { Server.MapPath("~/bin/MyNamespace.Data.dll") },
new AutoPersistenceModelGenerator().Generate(),
Server.MapPath("~/NHibernate.config"));
if (ConfigurationManager.AppSettings["DbGen"] == "true")
{
var export = new SchemaExport(cfg);
export.Execute(true, true, false, NHibernateSession.Current.Connection, File.CreateText(#"DDL.sql"));
}
}
The AutoPersistenceModelGenerator hooks up the various conventions, including a TableNameConvention like so:
public void Apply(FluentNHibernate.Conventions.Instances.IClassInstance instance)
{
instance.Table(Inflector.Net.Inflector.Pluralize(instance.EntityType.Name));
}
This is working nicely execpt that the sqlite db generated does not have pluralized table names.
Any idea what I'm missing?
Thanks.
Well, I'm not sure why this made a difference, but in the process of debugging, I did this, and now it works:
public void Apply(FluentNHibernate.Conventions.Instances.IClassInstance instance)
{
string tablename = Inflector.Net.Inflector.Pluralize(instance.EntityType.Name);
instance.Table(tablename);
System.Diagnostics.Debug.WriteLine(string.Format("Table = {0}", instance.TableName));
}

Resources