SqLite in memory database : CREATE TABLE does not work? - c#

When using this code on a SqLite file database, it works fine.
using (var ctx = new Test2010Entities())
{
string s = "CREATE TABLE 'Company' ([Id] integer PRIMARY KEY AUTOINCREMENT NOT NULL, varchar(50) NOT NULL);";
ctx.ExecuteStoreCommand(s);
ctx.Companies.AddObject(new Company { Code = "_1" });
ctx.Companies.AddObject(new Company { Code = "_2" });
ctx.SaveChanges();
foreach (var c in ctx.Companies.ToList())
{
Console.WriteLine(c.Code);
}
}
But when runnning this code on a SqLite 'In Memory' database (Data Source=:memory:;Version=3;New=True;) , I get this exception:
Unhandled Exception: System.Data.UpdateException: An error occurred
while updating the entries. See the inner exception for details. --->
System.Data.SQLite.SQLiteException: SQL logic error or missing
database no such table: Company
Note this is tested with VS 2010, EF 4.4.0.0 and sqlite-netFx40-setup-bundle-x86-2010-1.0.84.0
::: UPDATE :::
As Simon Svensson suggested, opening the connection before any other commands does do the trick:
ctx.Connection.Open();

This happens when your ORM closes your connection, and reopens it. That will reset the sqlite in-memory database to its default state; i.e. empty.
The same thing happens with NHibernate unless you set connection.release_mode = close (the default is after_transaction.
I'm not familiar with Entity Framework, but I expect a similar setting or using the DataContext(IDbConnection) constructor which is documented as "If you provide an open connection, the DataContext will not close it."
The same documentation also states "In a System.Transactions transaction, a DataContext will not open or close a connection to avoid promotion." which may be a cleaner solution.
Using some Reflector magic shows that it's SQLiteConnection.Open that calls (via SQLite3.Open) sqlite3_open_interop (if you're using the NuGet sqlite package). This shows that you get a new empty in-memory database everytime you call SQLiteConnection.Open.

Related

Unable to begin a distributed transaction using Entiy Framework

I'm having the following error executing this piece of code:
private bool _updateList(SysInfo _sysInfo, List<pList> _pList)
{
try
{
foreach (var p in _pList)
{
_context.spUpdatePListApprovalFlow(p.countryID, _sysInfo.User.JobRoleID, p.src, p.id, p.status, _sysInfo.User.Username);
}
return true;
}
catch (Exception ex) //debug only
{
throw; //throws error to the main try catch
}
}
ERROR
The operation could not be performed because OLE DB provider "MSDASQL"
for linked server "AS400_LINKEDSRV" was unable to begin a distributed
transaction.
However, everything works fine when I run the Stored Procedure in SQL Management Studio:
exec [dbo].[spUpdatePListApprovalFlow]
#CountryID = 123456,
#UserTypeID = 23456,
#Src = 1,
#Id = '123456789',
#Status = 30,
#Username = 'username'
I'm tired of digging for an answer nothing works... Few things I've tried:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
insert multiple transactions in the stored procedure
This sp has 2 sub stored procedures on it. One that writes into a table of the application's database, and another that updates a table in as400.
In EF6 stored procedures are called in an explicit transaction, by default. You can turn this off for a particular DbContext instance by changing its configuration after creating it, or for all instances of a DbContext type by changing it in the constructor. EG
using (var db = new Db())
{
db.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
//. . .
}
See: https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.dbcontextconfiguration.ensuretransactionsforfunctionsandcommands
Ok, after half a day trying to solve this I've finally solved it.
Resolution
Downgraded from Entity Framework 6 to Entity Framework 5 and the
distribuited transactions error has gone.
Just pay attention, if you're going to do this, you have to change some usings in your code. ( in auto generated code in the Data Model as well)
EF 6 uses
using System.Data.Entity.Core.Objects
EF 5 uses
using System.Data.Objects;
If you don't need distributed transactions you can try to disable them in the settings of the linked server:
EXEC master.dbo.sp_serveroption
#server=N'AS400_LINKEDSRV',
#optname=N'remote proc transaction promotion',
#optvalue=N'false'
Refer to this Microsoft page on Linked Servers.
Your System Administrator and/or DBA will probably need to make changes to address the missing linked server definition to your AS/400 server.
Another possible issue is that the AS/400 server (from IBM) lacks software support for the OLE DB data sources. This too would be something that the System Administration staff may need to address.

How to read External Sqllite Database in xamirin android in Visual Studio C#

My Code :
var dbpath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "ot.db3");
Context myContext = null;
try
{
var dbcon = new SQLiteConnection(dbpath);
var db= dbcon.Query<records>("SELECT * FROM records WHERE sno = ? ", "1");
int count = db.Count;
}
catch (IOException ex)
{
var reason = string.Format("The database failed to create - reason {0}", ex.Message);
Toast.MakeText(myContext, reason, ToastLength.Long).Show();
}
I Create a Sqlite Database from my SQL Server Database.
Now I save it to my Phone on this path (Android/Data/Application/File)
Now using Sqlite-net-pcl nugget package for Sqlite Connection the connection works fine showing have no error.
When I try to read a table from database this Give any error that "No Such Table exist in database". And the table exists in the database and is populated with data.
What can I do?
Thanks in advance
Why are you writing the SQL query? You could make it more simple, something like, conn.Get(id);
You will only need to add [PrimaryKey] to your PK in the model.
Also, I suggest you to not use SQLite.SQLiteConnection and use SQLiteAsyncConnection instead, so you will be able to get data using "await conn.GetAsync(id)" and this way it won't block the main thread.
Create a Blank Database – A database reference can be created by passing the file path the SQLiteConnection class constructor. You do not need to check if the file already exists – it will automatically be created if required, otherwise the existing database file will be opened.
var db = new SQLiteConnection (dbPath);
Save Data – Once you have created a SQLiteConnection object, database commands are executed by calling its methods, such as CreateTable and Insert like this:
db.CreateTable<Stock> ();
db.Insert (newStock); // after creating the newStock object
Retrieve Data – To retrieve an object (or a list of objects) use the following syntax:
var stock = db.Get<Stock>(5); // primary key id of 5
var stockList = db.Table<Stock>();
For more info use following link:
https://developer.xamarin.com/guides/android/application_fundamentals/data/part_3_using_sqlite_orm/#Using_SQLite.NET
You need to check in your DB file if the table really exists.
Extract the database from your Android device/simulator with ADB
Example: adb pull //.db .
It will download the DB file to your computer.
Then, use a tool such as "DB Browser for SQLite" (http://sqlitebrowser.org/) to open your DB file and check if your table exists.
Other common mistakes when using SQLite with Android are:
the file is not found (the path in your connectionstring is not good)
the name is not the one your think (maybe in your case, it is "Record" and not "Records")
Hope it will help.

Drop a database using entity framework

I'm trying to remove a database form my application using entity framework.
The code I use is the following:
using (var dbContext = container.Resolve<ApplicationDbContext>())
{
dbContext.Database.Delete();
}
According to msdn this should work but nothing happens.
the dbContext is registered using ContainerControlledLifetimeManager and should be the same instance used to create the DB.
Adding, updating and deleting instances of entity types needs dbContext.SaveChanges() to reflect changes.
However dbContext.Database.Delete() does not need dbContext.SaveChanges().
If you open connection for example from Sql Management Studio to your database and try to dbContext.Database.Delete() then you receive Cannot drop database "dbContext" because it is currently in use. If you restart you sql server, you drop those connections and then retry dbContext.Database.Delete() you successfully drop database.
Last thing is refresh database list in Sql Management Studio in order to see that database is not there any more.
Testing with this code snippet:
using (var dbContext = new dbContext())
{
dbContext.Database.Delete();
}
After #moguzalp and this (MSDN Database.Delete Function), I came with a solution for my case:
using System.Data.Entity;
Database.Delete("connectionStringOrName");
In my case I was trying to Recreate a mssqllocalDb database for test purposes. But whenever I used the same DbContext (or an immediately new one, disposing the first and opening another), it looked like the database was still up when I tried to create it.
Bad Example: (x)
public static void RecreateDatabase(string schemaScript)
{
using (DbContext context = new DbContext("connectionStringName"))
{
context.Database.Delete(); // Delete returns true, but...
Database database = context.Database;
database.Create(); // Database already exists!
database.ExecuteSqlCommand(schemaScript);
}
}
Working example: (/)
public static void RecreateDatabase(string schemaScript)
{
Database.Delete(); // Opens and disposes its own connection
using (DbContext context = new DbContext("connectionStringName")) // New connection
{
Database database = context.Database;
database.Create(); // Works!
database.ExecuteSqlCommand(schemaScript);
}
}
Context: I'm using this on an [AssemblyInitialize] function to test my ModelContexts
All of your changes occurred on local variable dbcontext.
That is final kick > add dbContext.SaveChanges(); at the end of your using block like so:
using (var dbContext = container.Resolve<ApplicationDbContext>())
{
dbContext.Database.Delete();
dbContext.SaveChanges();
}

Howto to access the tables of an attached database?

I am using sqlite-winrt on a Windows Phone 8 project to work with SQLite databases. Works quite will, except a problem with attached databases:
There are two identical database (same tables, different content) A and B. B is attached to A:
database dbA = new Database(dbAFile);
await dbA.OpenAsync();
await dbA.ExecuteStatementAsync("ATTACH B.sqlite AS AttachDB");
query = "SELECT * FROM SomeTable";
using (Statement sqlStatement = await dbA.PrepareStatementAsync(query)) {
while (await sqlStatement.StepAsync()) {
...List Content of SomeTable in Table A --> No Problem
}
}
query = "SELECT * FROM AttachDB.SomeTable";
using (Statement sqlStatement = await dbA.PrepareStatementAsync(query)) {
while (await sqlStatement.StepAsync()) {
...List Content of SomeTable in Table B --> Crash in PrepareStatementAsync
}
}
When using to access the Table "SomeTable" in the attached database an Exception is thrown when preparing the statment. The Exception does not show the source of the problem but I managed to get the SQL error message, which is:
"no such table: AttachDB.SomeTable"
Of course database B has a Table "SomeTable". When I connect to this database directly I can access table "SomeTable" without any problem.
I thought that I could be a problem that B has exactly the same tables as A and create a table "OnlyInB" in B. But accessing AttachDB.OnlyInB also fails. According to the sqlite doc one can skip the database name when the table name is unique. Thus "OnlyInB" should work as well. But is does not. "SELECT * FROM OnlyInB" shows "no such table: OnlyInB"
I testes the same scenation with the "SQLite Manager" Extension of Firefox (opened A, attached, B...) Selecting Data from AttachDB.SomeTable or any other table in B is not problem there. The Problem only occurs when using sqlite-winrt.
I also tested if there could be any problem with attaching B to A. But there isn't. When I try to attach B twice or to attach a third database using "AttachDB" again an error is shown that clearly states that B is correctly attached to A. The attaching seems to work perfect, except the problem that I cannot access any tables in B...
Any advise?
Thank you very much!
This statement:
ATTACH B.sqlite AS AttachDB
is not valid SQL; the file name must be a string.
In any case, you should always include the full path to the database file; otherwise, SQLite will open the database in the current path, and, if the file does not exist, try to create a new, empty database:
ATTACH '/some/where/B.sqlite' AS AttachDB

EntityFramework CodeFirst and EDMX together in TransactionScope

I need to combine in one application
code generated from DB to EDMX file before compilation and
code generated and compiled during runtime by application itself, where generated code uses CodeFirst to access DB.
Remark: Codes in 1. and 2. have different DbContexts, access same database, but different tables.
It looks, that when I am using instances of type 1. and 2. in different transaction scopes, everything works fine. But when I try to use them together in one transaction scope, I get error (in case when EDMX is called first)
System.Reflection.TargetInvocationException: Exception has been thrown by the ta
rget of an invocation. ---> System.Data.ProviderIncompatibleException: An error
occurred while getting provider information from the database. This can be cause
d by Entity Framework using an incorrect connection string. Check the inner exce
ptions for details and ensure that the connection string is correct. ---> System
.Data.ProviderIncompatibleException: **The provider did not return a ProviderManif
estToken string.** ---> System.Transactions.TransactionException: **The operation is
not valid for the state of the transaction.**
and error (in case when CodeFirst is used first)
System.Data.MetadataException: Schema specified is not valid. Errors:
(0,0) : error 0175: **The specified store provider cannot be found in the configur
ation, or is not valid.**
at System.Data.Metadata.Edm.StoreItemCollection.Loader.ThrowOnNonWarningErrors()
To complicate my situation even more I have to add this: described behaviour I have only in case when DB is on remote server. If I am working with local DB, everything looks OK. My suspicion is that Distributed Transaction Coordinator can play its role...
Main question: is it possible to combine EDMX and CodeFirst in one TransactionScope. If yes then how?
Any help would be appreciated. Milos
CodeFirst creates an EDMX based on your classes and it's not possible to load an exisiting edmx file. However you can generate classes from your database (e.g. using EF Power Tools) and configure your model so that the EDMX generated by your CodeFirst app is the same as the one you would like to load. You can use TransactionScope with Entity Framework. The error messages you are getting are not related to transaction scope but to a missing or incorrectly used provider.
I used code first to save to two different databases came up with errors connection string was wrong so i did this and it worked....
try
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
MegaBotExtractorDBContext2 db = new MegaBotExtractorDBContext2();
MegaBotExtractorDBContext db1 = new MegaBotExtractorDBContext();
FullUri newUri = new FullUri();
HostUri NewHostUri = new HostUri { HostUriName = "google10.com" };
db1.HostUris.Add(NewHostUri);
db1.SaveChanges();
using (TransactionScope ts2 = new TransactionScope(TransactionScopeOption.RequiresNew))
{
db.FullUris.Add(newUri);
db.SaveChanges();
ts2.Complete();
ts.Complete();
}
}
}
catch { }

Categories

Resources