I have an SQLite3 database that contains multiple choice questions. I am able to very quickly and easily use this database in both my Android and iOS applications. However, I have come to write a Windows Phone 8.1 version of apps and I'm finding the process much more difficult.
I have added a couple of packages and references to my project. I have used nuget to add two packages, sqlite-net and System.Data.SQLite, and I have also added a reference to SQLite for Windows Phone 8.1.
I have dropped my database file into the project's Assets folder. It's called questionsDb.db. I have changed its build actions property to content and set the option to always copy.
I have written the following model class:
using SQLite;
namespace MyApp
{
class Question
{
[PrimaryKey,AutoIncrement]
public int _id { get; set; }
[Indexed]
public string question { get; set; }
public string answer { get; set; }
public string incorrect1 { get; set; }
public string incorrect2 { get; set; }
public string incorrect3 { get; set; }
public int difficulty { get; set; }
}
}
I then have the following code which is intended to open the database and select the first question:
var db = new SQLite.SQLiteConnection( ApplicationData.Current.LocalFolder.Path + "\\questionsDb.db");
Question q = new Question();
q = db.Query<Question>("select * from questions where _id = 1")[0];
When I run this code SQLite does try to open a database, but I get an error message saying:
Additional information: Could not open database file: C:\Data\Users\DefApps\APPDATA\Local\Packages\3697fbe8-2d3f-455f-ad78-2bce9035bd82_gd9wj2p7c52jg\LocalState\questionsDb.db (CannotOpen)
I have tried numerous different file paths for the database, such as:
questionsDb.db
Assets\questionsDb.db
ApplicationData.Current.LocalFolder.Path + "\Assets\questionsDb.db"
I am very new to Windows Phone so this may be a simple fix, but I'd be very grateful if someone could point me in the right direction.
Files which build action is set to Content are copied to the app's folder. So you need to copy the database to the appdata folder.
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///questionsDb.db"));
// You can open the file now, using file.Path, but files in the app's folder are read-only
// so you better to copy it to the local storage
var copiedFile = await file.CopyAsync(ApplicationData.Current.LocalFolder);
// Now you can open the database
var db = new SQLite.SQLiteConnection(copiedFile.Path);
Question q = new Question();
q = db.Query<Question>("select * from questions where _id = 1")[0];
Related
I created an ASP.NET Core project in IBM Bluemix and added a connection to a Compose for MySQL MySQL database
I cloned the project from the git repository on hub.jazz.com in Visual Studio 2015 and I want to generate the database from the context that I create but I can't connect to the database.
using HunterViews.Domain.Entities;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace HunterViews.Data
{
public class HunterViewsContext : DbContext
{
public HunterViewsContext(DbContextOptions<HunterViewsContext> options) : base(options)
{
}
public HunterViewsContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=HunterViewsCore;Trusted_Connection=true;");
}
public DbSet<User> users { get; set; }
public DbSet<JobSeeker> jobseekers { get; set; }
public DbSet<HeadHunter> headHunters { get; set; }
public DbSet<Offer> offers { get; set; }
public DbSet<Post> posts { get; set; }
public DbSet<Skill> skills { get; set; }
public DbSet<Reclamation> reclamations { get; set; }
public DbSet<Evaluation> evaluations { get; set; }
public DbSet<Formation> formations { get; set; }
public DbSet<Notification> notifications { get; set; }
public DbSet<Certification> certifications { get; set; }
}
}
So, I want to change optionsBuilder : optionsBuilder.UseSqlServer(#"Server(localdb)\mssqllocaldb;Database=HunterViewsCore;Trusted_Connection=true;");
to use the MySQL database I've created on Bluemix to generate my DB. How can I do this?
To use MySQL instead of SQL Server, you'll need to include one of the MySQL providers for Entity Framework Core in your project. In Visual Studio 2015, this means modifying your project.json file to include the dependency. Which dependency you add depends on which provider you choose to use. For example, if you choose to use SapientGuardian, you would add SapientGuardian.EntityFrameworkCore.MySql to your project.json's dependencies section like so:
"dependencies": {
"SapientGuardian.EntityFrameworkCore.MySql": "7.1.19"
}
The standard convention for ASP.NET Core is to do configuration in the Startup class, but you can also configure the database connection string in your DbContext as you're doing in the example that you posted. To configure in the Startup class (assuming your connection string is stored in a string variable named connectionString, modify the line where you add your DbContext to this:
app.AddDbContext<HunterViewsContext>(options => options.UseMySQL(connectionString));
By doing that you will no longer need to override the OnConfiguring method in your DbContext. But if you would like to use OnConfiguring in the DbContext instead, you can simply call optionsBuilder.UseMySQL(connectionString) there instead.
Now here's where it gets a bit tricky. Since the Compose for MySQL services use self-signed SSL certificates which are provided as a Base64-encoded string representing the PEM format certificate in the VCAP_SERVICES environment variable, you'll need to convert that certificate to PFX format before you can use it with the MySQL provider.
You have two options for doing this conversion. The first option is to use some external tool to convert the certificate to PFX format and push that file with your application. The other solution is to convert the certificate on the fly at application startup when you configure the database connection.
You can use the BouncyCastle NuGet package to do the conversion on the fly like so:
private static void CreatePfxFromPemCertificate(string base64encodedPem, string pfxFilePath, string pfxPassword)
{
// get the PEM certificate, then convert to pfx format
byte[] bytes = Convert.FromBase64String(base64encodedPem);
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
X509CertificateEntry[] chain = new X509CertificateEntry[1];
object pemObject;
using (var streamReader = new StreamReader(new MemoryStream(bytes)))
{
PemReader pemReader = new PemReader(streamReader);
if ((pemObject = pemReader.ReadObject()) is X509Certificate)
{
chain[0] = new X509CertificateEntry((X509Certificate)pemObject);
}
}
store.SetCertificateEntry(pfxFilePath, chain[0]);
var certFile = File.Create(pfxFilePath);
store.Save(certFile, pfxPassword.ToCharArray(), new SecureRandom());
certFile.Flush();
certFile.Dispose();
}
This function will require these using statements:
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
And this dependency in project.json:
"Portable.BouncyCastle-Signed": "1.7.0.2",
This function accepts 3 parameters:
The Base64-encoded string (provided in VCAP_SERVICES environment variable)
The path to the pfx file that will be written
The password that should be used to protect the pfx file
Now that we have a function which can convert the Base64-encoded certificate, it's time to put it all together and create the connection string from the VCAP_SERVICES environment variable in the Startup class.
First, in the constructor of the Startup class:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("vcap-local.json", optional:true); // when running locally, store VCAP_SERVICES credentials in vcap-local.json
Configuration = builder.Build();
// try to get the VCAP_SERVICES environment variable (when running on Bluemix)
string vcapServices = Environment.GetEnvironmentVariable("VCAP_SERVICES");
if (vcapServices != null)
{
JObject json = JObject.Parse(vcapServices);
var credentialsToken = json.SelectToken("compose-for-mysql")? // look for compose-for-mysql instance
.FirstOrDefault()? // get first database instance
.SelectToken("credentials"); // get the credentials
// get the uri
Configuration["compose-for-mysql:0:credentials:uri"] = credentialsToken?.SelectToken("uri");
// get the base64 certificate
Configuration["compose-for-mysql:0:credentials:ca_certificate_base64"] = credentialsToken?.SelectToken("ca_certificate_base64");
}
}
This code will grab the database Uri from the VCAP_SERVICES environment variable, or a json file called vcap-local.json in your project directory if you're running locally (you can copy the credentials from the connections tab in the Bluemix UI).
To put this all together to create the database string in your ConfigureServices method in the Startup class:
public void ConfigureServices(IServiceCollection services)
{
var databaseUri = Configuration["compose-for-mysql:0:credentials:uri"];
var username = (databaseUri.Split('/')[2]).Split(':')[0];
var password = (databaseUri.Split(':')[2]).Split('#')[0];
var port = (databaseUri.Split(':')[3]).Split('/')[0];
var hostname = (databaseUri.Split('#')[1]).Split(':')[0];
var database = databaseUri.Split('/')[3];
// create the connection string
var connectionString = $"Server={hostname};Port={port};uid={username};pwd={password};Database={database};SSL Mode=Required;";
// convert the Base64 encoded PEM SSL certificate to PFX format
CreatePfxFromPemCertificate(config[$"compose-for-mysql:0:credentials:ca_certificate_base64"],
"compose-for-mysql0.pfx", password);
// add the ssl certificate to the connection string
connectionString += "CertificateFile=compose-for-mysql0.pfx;";
connectionString += $"CertificatePassword={password};";
// add database context
services.AddDbContext<HunterViewsContext>(options => options.UseMySQL(connectionString));
// Add framework services.
services.AddMvc();
}
I'm building a fairly small ASP.NET MVC 5 app using EF 6 and MySQL, and I thought it'd be nice to use Identity instead of rolling-my-own security. I've been at it for days, trying everything I can Google up, but I feel the .NET universe expanding around me. I'm no further ahead.
I simply need login accounts and security for a section of the site I'm building. Some pages are private to subscribers and others are public. I'd like for the Identity tables to be in the same MySQL db that the app utilizes.
The last time I attempted anything like this was the FormsAuth/Membership stuff in ASP.NET 2.0 - and I haven't built anything substantial w/ .NET since then - so very much a beginner w/ Identity.
Here's now this experiment has progressed. I got MySQL working with EF 6 through a series of guides and hacks, and arrived at this for the Code First approach, and worked. Tables were getting generated and data was flowing:
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class RwcDataModel : DbContext
{
public RwcDataModel()
: base("name=RwcDataModel")
{
}
public virtual DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
[Table("user")]
public class User
{
[Key, Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int Id { get; set; }
[Column("fullname"), StringLength(45, MinimumLength = 1)]
public virtual string FullName { get; set; }
[Column("email"), StringLength(45, MinimumLength = 1)]
public virtual string Email { get; set; }
[Column("username"), StringLength(45, MinimumLength = 1)]
public virtual string Username { get; set; }
[Column("password"), StringLength(45, MinimumLength = 1)]
public virtual string Password { get; set; }
[Column("created"), DataType(DataType.Date)]
public virtual DateTime Created { get; set; }
[Column("active")]
public virtual bool Active { get; set; }
}
//...etc - other tables
public class RwcDbInitializer : DropCreateDatabaseAlways<RwcDataModel>
{
protected override void Seed(RwcDataModel context)
{
context.Users.Add(new User { FullName = "Administrator", Email = "me#gmail.com", Username = "Administrator", Password = "password", Created = DateTime.Now });
context.Users.Add(new User { FullName = "Some Guy", Email = "someguy#gmail.com", Username = "someguy", Password = "password", Created = DateTime.Now });
context.SaveChanges();
}
}
...with this in Application_Start() of the Global class:
DbConfiguration.SetConfiguration(new MySqlEFConfiguration());
Database.SetInitializer<RwcDataModel>(new RwcDbInitializer());
I first tried this:
http://www.codeproject.com/Tips/788357/How-to-set-up-application-using-ASP-NET-Identity-w
...but this just caused my db to be dropped, but not re-created and seeded. Strange, can't explain that.
Thanks to trailmax below, I followed these (similar) instructions:
http://www.asp.net/identity/overview/getting-started/aspnet-identity-using-mysql-storage-with-an-entityframework-mysql-provider
...but upon running this iteration of my app, no Identity tables are created. Also, the RwcDataModel above does nothing. The db isn't dropped - it's as if the Initializer is being ignored completely.
Any ideas how to proceed? Thanks!
Check out this blog ASP.NET Identity 2.1 with ASP.NET Web API 2.2 ASP.NET Identity 2.1 with ASP.NET Web API 2.2. Mr. Taiseer Joudeh does a great job of explaining how to use ASP.net Identity 2.1 with the Entity Framework. There is sample code included with the tutorial. While MySQL is not used in the tutorial, the Entity Framework makes it easy to switch to MySQL. Hope this helps. Cheers.
I am developing an application in widows phone 8,in my application I have to create a database .how can I do this ,I am new to this.please help me out
Well, that depends on what backend you want, if you are going to store small amounts of data I would recommend that you create an xml file in local storage. If you are looking at something more complex, you can use Linq-to-SQL with SQL Server CE.
The code to generate such a database involves creating a DataContext class similar to this:
public class MyDbContext : DataContext
{
public const string MyDbConnString = "isostore:/MyDb.sdf";
public MyDbContext(string pConnString = MyDbConnString) : base(pConnString) { }
public Table<SomeClass1> table1;
public Table<SomeClass2> table2;
}
Then you would create the classes that will function as "tables" like this:
[Table(Name = "MyTable")]
public class SomeClass1
{
[Column(IsPrimaryKey = true, Name = "ID")]
public int Id { get; set; }
[Column(Name = "Name")]
public string Name { get; set; }
}
Lastly in the App.xaml.cs you would place code to create the database in the constructor:
public App()
{
// ... other code
CreateDatabase();
}
private void CreateDatabase()
{
using (var context = new MyDbContext())
{
if (!context.DatabaseExists())
{
context.CreateDatabase();
}
}
}
Note that if you want an in depth explanation of how the classes need to be set up, if you want to create foreign key references for example, you need to look at the MS documentation.
I would recommend starting here.
Note: While I target Windows Phone 7, it doesn't introduce anything besides a size restriction.
In an attempt to write a GPS / Routing / Map application for the Windows Phone 7, I'm trying to attempt to use OpenStreetMap for this and I want to get my data stored in a SQL Server Compact Edition database on my Windows Phone 7. This is giving me a lot of trouble so I'm getting clueless what the right way is...
Here is my progress:
I've downloaded Belgium.osm.pbf, which contains all the Belgium OSM data in PBF format.
Note that Belgium isn't that large, it's the country I live in so it seems as a good start.
It would be nice if my database were near the size of that PBF file, because it is only 80 MB...
Using Marc Gravell's protobuf-net, I now have written a parser which is giving me all the OSM data.
On a first attempt I tried to just load it all in memory but that seems to be too big for my Windows Phone 7, as it results in a size > 512 MB. Then the idea was that I needed a database to store this information in, so it seems logic to store this in a SQL Server Compact Edition sdf file.
Hence, I created the following DataContext and Tables in LINQ to SQL:
public class RoutingContext : DataContext
{
public RoutingContext()
#if WINDOWS_PHONE
: base("Data Source = 'isostore:/RoutingDB.sdf'; Max Database Size = 1024; Max Buffer Size = 65536")
#else
: base("Data Source = './RoutingDB.sdf'; Max Database Size = 1024; Max Buffer Size = 65536")
#endif
{
}
public Table<Node> Nodes;
public Table<Road> Roads;
public Table<RoadNode> RoadNodes;
public Table<NodeProperty> NodeProperties;
public Table<RoadProperty> RoadProperties;
public Table<StringData> Strings;
}
[Table]
public class Node
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
[Column()]
public int Lon { get; set; }
[Column()]
public int Lat { get; set; }
}
[Table]
public class NodeProperty
{
[Column()]
public int NodeId { get; set; }
[Column(DbType = "NVarChar(255) NOT NULL")]
public int Key { get; set; }
[Column(DbType = "NVarChar(255) NOT NULL")]
public int Value { get; set; }
}
[Table]
public class RoadProperty
{
[Column()]
public int RoadId { get; set; }
[Column(DbType = "NVarChar(255) NOT NULL")]
public int Key { get; set; }
[Column(DbType = "NVarChar(255) NOT NULL")]
public int Value { get; set; }
}
[Table]
public class Road
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
}
[Table]
public class RoadNode
{
[Column()]
public int RoadId { get; set; }
[Column()]
public int NodeId { get; set; }
}
[Table]
public class StringData
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
[Column(DbType = "NVarChar(255) NOT NULL")]
public String String { get; set; }
}
First I went on the InsertOnSubmitTour() with a SubmitChanges() every now and then, but that apparently is way to slow as SubmitChanges() inserts row-per-row. So then I went to try SqlBulkCopy which apparently doesn't work for SQL Server Compact Edition, this made me end up with SqlCeBulkCopy which seems to be faster but still is slow.
There are two problems that I am experiencing with this solution:
It is still pretty slow.
The resulting size is many times bigger. Please note that Belgium.osm.pbf is only ~80 MB. The .sdf however appears to be ~592 MB, is there anything I can do about this?
So, here are my questions:
Where did I completely go wrong? What should I do instead?
I find it really weird that it's so hard to process a 80 MB file properly. Please also note that I'm doing all this computing on my computer at the moment and once it runs fair on the computer I'll try it on the Windows Phone 7.
If there really is no handy LINQ solution, would it make sense to produce an indexed PBF?
This however requires me to reinvent what a database could already provide to me.
Would it make sense to increase the size on my computer, essentially making a writing a converter, then sent the ~592 MB .sdf database file to my phone?
This seems to be a last resort that's in between option 1 and 2, but that doesn't make the application upload-able to MarketPlace as it's quite nasty to have to convert on the computer in advance and then somehow get it onto the phone.
Please note that I focus on question 1 and that the other questions are merely solutions if that is shown to be impossible, I'm just missing something that would make this go fluent but I have no idea...
It makes sense to use a database for this. The size may be due to the compactness of the pbf file, also keep in mind that all data in SQL CE is unicode. Your question is unclear - what is slow? Also, you can try to Compact the database file after the import, it may shrink the file a bit. Depending on the resulting size, your .xap may still be small enough for MarketPlace. (As the .xap zips the sdf file as well)
I'm playing around with SQL Server Compact Edition 4 CTP1 as I'd like to use it as a datastore for a low-traffic web app. When I try to create a DataContext with a connection string specifying System.Data.SqlServerCe.4.0 (in order to use LINQ To SQL), I get the following error message:
Cannot open '|DataDirectory|\data.sdf'. Provider 'System.Data.SqlServerCe.3.5' not installed.
So why is my code not using version 4 of SQL CE?
Back story: I'm using Visual Web Developer Express 2010 for development, but I downloaded the WebMatrix beta and used its designer to create a SQL CE 4 .sdf file containing some test data.
Using the SqlCeConnection/SqlCeCommand/SqlCeDataReader classes, I've successfully created a basic MVC app which retrieves the test data and displays it. The SQL CE 4 binaries are copied into the app's bin folder. In my controller:
var connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString;
var tmp = new Dictionary<string, string>();
using(var conn = new SqlCeConnection(connectionString))
{
conn.Open();
using (SqlCeDataReader r = new SqlCeCommand("select * from ttest", conn).ExecuteReader())
{
while (r.Read())
{
tmp.Add(r["id"].ToString(), r["name"].ToString());
}
}
}
return View(new TestViewModel {
Items = tmp
});
The connection string in Web.config is as follows:
<add name="Main" connectionString="Data Source=|DataDirectory|\data.sdf" providerName="System.Data.SqlServerCe.4.0" />
This works perfectly, so I know the connection string is correct and that I've set up the binaries properly etc. So I thought I'd try out a bit of LINQ To SQL stuff, which is how I want to build the real app:
[Table(Name = "tTest")]
public class TestEntity
{
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int ID { get; set; }
[Column]
public string Name { get; set; }
}
public class Repository
{
private Table<TestEntity> testTable;
public Repository()
{
var connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString;
var context = new DataContext(connectionString);
testTable = context.GetTable<TestEntity>();
}
public IQueryable<TestEntity> TestEntities
{
get { return testTable; }
}
}
And then in the controller (db being a Repository constructed in the controller constructor):
var tmp = db.TestEntities.ToDictionary(x => x.ID.ToString(), x => x.Name);
return View(new TestViewModel {
Items = tmp
});
But when I view the page using this code, I get the aforementioned error:
Cannot open '|DataDirectory|\data.sdf'. Provider 'System.Data.SqlServerCe.3.5' not installed.
How can I force my app to use the correct version? Can anyone help?
LINQ to SQL is not supported by SQL Server Compact 4.0, only Entity Framework / LINQ to Entities. But if you pass a version 4 SqlCeConnection to the DataContext constructor, it will actually work!