Sql Ce & EF Usage (self coded) - entity-framework

I have a Windows Program which should be deployed without writing to AppData during Installation, but i want a Sql CE Database in there.
So i have 2 Ideas: Deploying it to Programs and then Copying on first start up, or, what i would prefer, Coding everything.
So i found this Thread Deploying VS2010 Database Projects Without VSDBCMD? which basically tells me its a bad idea, but i don`t think the Answerer is allknowing and i have a better Idea. I found that Piece of Code somewhere:
string connStr = "Data Source = FooDatabase.sdf; Password = SomePassword";
if (File.Exists("FooDatabase.sdf"))
File.Delete("FooDatabase.sdf");
SqlCeEngine engine = new SqlCeEngine(connStr);
engine.CreateDatabase();
using (var conn = new SqlCeConnection(connStr)) {
conn.Open();
SqlCeCommand cmd = conn.CreateCommand();
cmd.CommandText = "CREATE TABLE FooTable(col1 int, col2 ntext)";
cmd.ExecuteNonQuery();
from here: Create SQLCE database programmatically
what i am asking is, if this works on any PC and what i have to do code to use Entity Framework. I was thinking of something like
public class FooContext : System.Data.Entity.DbContext
{
public FooContext() : base("Data Source = FooDatabase.sdf; Password = SomePassword") { }
public DbSet<FooTable> FooTables { get; set; }
}
public class FooTable
{
public int col1 { get; set; }
public string col2 { get; set; }
}
but i just dont get it to work.
might be that only the connectionstring is wrong, but how do i avoid using it or how does the right one look like?
Help plz?

Try to use this in your startup logic
private static void InitializeDB()
{
const string connectionString = "Data Source = FooDatabase.sdf; Password = 123";
Database.DefaultConnectionFactory = new
SqlCeConnectionFactory("System.Data.SqlServerCe.4.0", "", connectionString);
}
take a look at this post

Related

Blazor 6.0 await HttpClient.GetFromJsonAsync<List CS8601 Possible null reference asignment

Hello Everyone im missing something fairly fundamental here and i could really appreciate some guidance .
I am fairly new to Blazor and the entity framework and am building one of my first Blazor apps
I have a fairly basic data class
using System.ComponentModel.DataAnnotations;
namespace BIDM2.Data
{
public class InvalidAddressMapping
{
[Key]
public int record_no { get; set; } = 0;
public string sales_org_pos { get; set; } = " ";
public string press_sales_mgr_code { get; set; } = " ";
public string press_sales_mgr_Name { get; set; } = " ";
public string forming_sales_rep_code { get; set; } = " ";
public string forming_sales_rep_Name { get; set; } = " ";
}
}
that i am using in my controller as follows
[HttpGet]
public async Task <ActionResult<List<InvalidAddressMapping>>> GetInvalidAdressMappings()
{
return await _db.GetInvalidAddressMappings.FromSqlRaw("EXEC BIDM_GetInvalidAddressMappings;").ToListAsync();
}
and im trying to use it in my razor page like this
#code {
List<InvalidAddressMapping> invalidMappings = new List<InvalidAddressMapping>();
protected override async Task OnInitializedAsync()
{
invalidMappings = await HttpClient.GetFromJsonAsync<List<InvalidAddressMapping>>(NavigationManager.BaseUri + "invalidmapping");
}
}
how ever when i try and run my razor page im getting an error CS8601 Possible null Reference asignment :(
Im not sure i totaly understand and i could use some guidance to point me in the right direction it has to be somethign fairly fundamental i am missing
interestingly this all came about because im trying to convert an existing non async method to an async method
when i use
//1. get invalid address mappings
public InvalidAddressMapping[] GetInvalidAddressMappings()
{
InvalidAddressMapping[] invMappings;
// exec BIDM_GetInvalidAddressMappings calls the stored procedure
invMappings = _dbcontext.GetInvalidAddressMappings.FromSqlRaw("EXEC BIDM_GetInvalidAddressMappings;").ToArray();
return invMappings;
}
}
it works beautifully and i can see a lovely list of JSON data
please help a struggling old git out and pint me in a direction where i can understand where i am going wrong :)
thank you every one
The GetFromJsonAsync extension method returns a nullable type. In your case, it is List<InvalidAddressMapping>? (note the extra ? on the end there). If it fails to deserialise properly, for example, it could return null. The code is telling you that you need to check for a null response to be safe.
So the safe version is to do something like this:
var result = await HttpClient.GetFromJsonAsync<List<InvalidAddressMapping>>(
NavigationManager.BaseUri + "invalidmapping");
if(result == null)
{
// Do something here to handle this error, for example:
throw new Exception("Can't get data from the server for some reason, help!");
}
invalidMappings = result;
Also note that the CS8601 message you see is a warning, not an error. So technically you could ignore it, though I would strongly advise against doing that.

SocketException while trying SaveChanges on a list of blobs with Entity Framework and MariaDB using Pomelo NUGET package

I would like to switch from SQLExpress to MariaDB, but run into an issue with SaveChanges.
I can replicate the exception related to the byte[] with a console test application easily using this code, which runs perfectly if I try the same on SQLExpress.
What puzzles me is:
TestScenario 1: Put the byte[] into TestTable class, it works with MariaDB.
TestScenario 2: Replace the list of SubTable with just one instance of subtable. -> Works
TestScenario 3: Replace the byte[] in SubTable by e.g. a single int -> again works
Each time I used add-migration and update-database prior to running the code.
The error message I am getting is:
"SocketException: Eine bestehende Verbindung wurde softwaregesteuert
durch den Hostcomputer abgebrochen."
"SocketException: Failed to read the result set."
I am using the latest version from Pomelo as well as EFCore via NUGET manager.
Honestly I am at a loss. The only information I could find on google was to check the maximum package size setting, but this is well above the blob size for my DB.
So here is my code:
A simple TestTable class with a List of SubTables.
public class TestTable
{
public int ID { get; set; }
public List<SubTable> sub { get; set; } = new List<SubTable>();
}
public class SubTable
{
public int ID { get; set; }
public int ParentID { get; set; }
public SubTable Parent { get; set; } //<- see Update Mai, 19th, 2020 below
public byte[] blob { get; set; } //<- here is the root cause for the issue (see Update Mai, 19th, 2020)
}
SubTable contains the blob as an array of bytes.
The ModelContext is derived from DBContext so nothing fancy here. Just the connection string, which needs to be adapted to the specific system.
public partial class ModelContext : DbContext
{
public DbSet<TestTable> TestData { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySql(#"Server=<IP>;Database=<DB>;User Id=<ID>;Password=<PW>;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
In the main part of the console app, I create the ModelContext and initialize my datastructure. I am using Code-First approach, having the database created by using add-migration and update-database.
class Program
{
static void Main(string[] args)
{
using (var db = new ModelContext())
{
TestTable t = new TestTable();
for (int index = 0; index < 4000; index++)
t.sub.Add(new SubTable() { blob = new byte[5000] });
db.TestData.Add(t);
db.SaveChanges(); // <- at this point the exception is raised
}
Console.WriteLine("Done!");
}
}
}
This is how the migration part of subtable looks like:
migrationBuilder.CreateTable(
name: "SubTable",
columns: table => new
{
ID = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
ParentID = table.Column<int>(nullable: false),
blob = table.Column<byte[]>(nullable: true),
TestTableID = table.Column<int>(nullable: true)
},
So basically this is a standard scenario which can be found on numerous web sites and blogs, if there would not be the exception, which I do not understand.
Any help/suggestions apprechiated.
UPDATE 2020 Mai 19:
Out of curiosity, I again tried to solve the issue. So I installed the newest version of MariaDB.
I received an error message indicating something is wrong with the
foreign key design.
Double checking the foreign key, I found a bug
in my code. public SubTable Parent { get; set; } should be:
public TestTable Parent { get; set; }
--> Now it works just fine with the newest version of MariaDB.
The MariaDB version (V5.5.xx) running on my NAS won't though. Sad but definetly not a show stopper.
So for me the issue is closed, as it seems to be related to an outdated version of MariaDB.
Cheers,
Axel

SCOPE_IDENTITY Exception

I have been evaluating the use of dapper and the simplecrud extension with sqlite. No matter what I try when doing a table insert things fail with an exception
no such function SCOPE_IDENTITY
Table class
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
Simplest piece of code to test
static void Main( string[] args )
{
SQLiteConnection conn = new SQLiteConnection( "Data Source=E:\\Databases\\MyDatabase.db;Version=3" );
conn.Open();
var usr = new User { Name = "Dave", Age = 65 };
var id = conn.Insert(usr);
conn.Close();
}
As indicated earlier when I run the code the data is inserted into the table but the program terminates with the SCOPE_IDENTITY exception.
Any assistance would be greatly appreciated
Judging from the Github page, it seems the current release has dropped support for SQLite:
Database support
There is an option to change database dialect. Default is Microsoft SQL Server but can be changed to PostgreSQL or MySQL. We dropped SQLite support with the .Net Core release.
SimpleCRUD.SetDialect(SimpleCRUD.Dialect.PostgreSQL);
SimpleCRUD.SetDialect(SimpleCRUD.Dialect.MySQL);
Depending on which version you have, you might be able to use a similar call to set the SQLite "dialect" (if it's still supported in your code base).
i was using dapper fastCrud i face the same issue. so add this line of code in my constructor.
OrmConfiguration.DefaultDialect = SqlDialect.SqLite;

entity framework cannot open database

I'm following the EF - Code First example at http://msdn.microsoft.com/en-us/data/jj193542.aspx. This example works fine. The example creates a LocalDB on my harddrive containing the database files .mdf and .ldf.
If I delete these 2 files, I get a Cannot open database exception, if I replace the files, it works. If I change the name of my DbContext and it will work.
Heres my question:
Why do I not get an exception when I first run the example ? Something somewhere appears to remember the filename/context name. What is the correct way to handle this ?
Class and DBContext below, exception throw at db.Blogs.Add(blog);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
class Program
{
static void Main(string[] args)
{
using (var db = new BloggingContext())
{
// Create and save a new Blog
Console.Write("Enter a name for a new Blog: ");
var name = Console.ReadLine();
var blog = new Blog { Name = name };
db.Blogs.Add(blog);
db.SaveChanges();
// Display all Blogs from the database
var query = from b in db.Blogs
orderby b.Name
select b;
Console.WriteLine("All blogs in the database:");
foreach (var item in query)
{
Console.WriteLine(item.Name);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public virtual List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
}
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
This actually doesn't have anything to do with your code. LocalDB will create a new database for you if one doesn't exist. The problem with removing the mdf/ldf files is that you're deleting the files without letting LocalDB know. So as far as it's concerned, the database still exists but the files backing the database are missing.
To delete a LocalDB database properly, use Server Explorer or SQL Object Explorer in Visual Studio (SQL Management Studio should work too). If the database file is in the app_data folder of your web project, deleting the file from Solution Explorer should properly delete the database as well.
What I was really trying to do was understand how/where a database is generated via a Code First approach. After some research, it turns out its pretty simple. All you need to do is create a connection string in your app.config or web.config file, something along the lines of ...
<connectionStrings>
<add name = YourDBContextName
providerName = "System.Data.SqlClient"
connectionString = "Data Source = (localdb)\v11.0; AttachDbFilename = Path to MDF file ...
The AttachDbFile specifies where the database will be created. You have to also name the connection the same as your database context.

Can't Get EF 6 Code First To Create the Tables

I already have a database with tables outside EF scope. But I want that the tables which will be used by EF to be created automatically.
public class SessionInfo
{
public Guid Id {get;set;}
public string Name { get; set; }
public DateTime StartsOn { get; set; }
public DateTime EndsOn { get; set; }
public string Notes { get; set; }
}
public class StudentsDbContext:DbContext
{
public StudentsDbContext():base("name=memory")
{
Database.Log = s => this.LogDebug(s);
}
public DbSet<SessionInfo> Sessions { get; set; }
}
This code just throws an exception because the table SessionInfoes doesn't exist.
using (var db = new StudentsDbContext())
{
db.Sessions.Add(new SessionInfo() {Id = Guid.NewGuid(), Name = "bla"});
var st = db.Sessions.FirstOrDefault();
}
What do I need to do so that EF will create the "SessionInfoes" (whatever name, it's not important) table by itself? I was under the impression that Ef will create the tables when the context is first used for a change or a query.
Update
After some digging, it seems that EF and Sqlite don't play very nice together i.e at most you can use EF to do queries but that's it. No table creation, no adding entities.
EF needs additional information in order to do this. You'll have to specify an IDatabaseInitializer first. Take a look at this list and find one that is appropriate for your needs (for example: MigrateDatabaseToLatestVersion, DropCreateDatabaseAlways, DropCreateDatabaseIfModelChanges, etc).
Then create your class:
public class MyDatabaseInitializer : MigrateDatabaseToLatestVersion
<MyDbContext,
MyDatabaseMigrationConfiguration>
Then also create the configuration for the initializer (ugh right?):
public class DatabaseMigrationsConfiguration
: DbMigrationsConfiguration<MyDbContext>
{
public DatabaseMigrationsConfiguration()
{
this.AutomaticMigrationDataLossAllowed = true;
this.AutomaticMigrationsEnabled = true;
}
protected override void Seed(MyDbContext context)
{
// Need data automagically added/update to the DB
// during initialization?
base.Seed(context);
}
}
Then one way to initialize the database is:
var myContext = new MyDbContext(/*connectionString*/);
Database.SetInitializer<MyDbContext>(new MyDatabaseInitializer());
myContext.Database.Initialize(true);
Some people prefer the to use the command line to migrate databases, but I don't want to assume I'll always have access to the database from a command lin.