How do I define Entity Framework provider in code? - entity-framework

I am using the JetEntityFrameworkProvider. I am trying to connect to an MS Access file (it has ext .sep but it is indeed an Access file).
I am trying to define the connection string and provider in code, but it is not working. Before I run I get the following error:
Unable to determine the provider name for provider factory of type 'JetEntityFrameworkProvider.JetProviderFactory'. Make sure that the ADO.NET provider is installed or registered in the application config.
I do not wish to configure the provider in the config. Surely there is a way to do this.
When I do run it (yes it will build), I get this error:
System.InvalidOperationException: 'The 'Jet OLEDB:Database' provider is not registered on the local machine.'
Context class
public class ProjectContext : DbContext
{
private DbConnection con = new JetConnection();
public ProjectContext() : base(new JetConnection(""Provider=Microsoft.ACE.OLEDB.12.0;Data Source='C:\\Test-Project.sep'; Provider=Jet OLEDB:Database; Password=SEEME;""), true)
{
}
public DbSet<Component> Components { get; set; }
}
Entity class
public class Component
{
[Key]
[Column("Counter")]
public int Id { get; set; }
[Column("Name")]
public string Name { get; set; }
}

I solved this by changing the connection string to this.
public ProjectContext() : base(new JetConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source='C:\Test-Project.sep'; providerName=JetEntityFrameworkProvider; Password=SEEME;"), true)
{
}
However, I have a new problem and a new error so I will post a new question.

Related

How to add a parameterized DbContext to a Unit of work

I am trying to refactor my asp.net mvc + entity framework project to use repository pattern, and a unit of work. In the newest versions of asp.net mvc DbContext is creating automatically using a parameterized constructor, it looks like this:
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Course> Courses { get; set; }
}
How can I create an instance of this DbContext in unitOfWork class, what options should I write it the brackets?
P.S: I can't remove the parameters, cause they are used in program.cs in the next way
builder.Services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext") ?? throw new InvalidOperationException("Connection string 'SchoolContext' not found.")));
And I also can't add an emty constuctor, cause it will cause an error due to the above statement. (you can't have both constructors)
Thanks to the comments I figured it out, here what I was looking for:
In the class create an instance of context
private SchoolContext _context;
And then initialize it using a constructor like this
public UnitOfWork()
{
var contextOptions = new DbContextOptionsBuilder<SchoolContext>()
.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=Mentoring.Data;Trusted_Connection=True;MultipleActiveResultSets=true")
.Options;
_context = new SchoolContext(contextOptions);
}

How to retrieve an IxxxSettings(an IOptions<..>) before the app is built?

I've an Asp.Net 6 app. In one of my package I configure some services that will be available.
One of the services will require to read some configurations of my settings.
So I've created the follow settings class(and the according interface):
public class MongoDbSettings : IMongoDbSettings
{
public string Host { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Port { get; set; }
public string ConnectionString => $"mongodb://{UserName}:{Password}#{Host}:{Port}";
}
I'm registering it like this:
public static IServiceCollection ConfigureInfrastructureServices(this IServiceCollection services,
IConfiguration configuration)
{
services.Configure<MongoDbSettings>(configuration.GetSection("MongoDbSettings"));
services.AddSingleton<IMongoDbSettings>(serviceProvider => serviceProvider.GetRequiredService<IOptions<MongoDbSettings>>().Value);
//Here I'm trying to add some code
}
This IMongoDbSettings will be used at multiple place(repository and Asp.Net Identity).
Just below, I'm trying to setup Asp.Net Core Identity for mongo db:
services.AddIdentityMongoDbProvider<User, Role, Guid>(
identityOption => { identityOption.Password.RequiredLength = 8; },
mongoOptions => { mongoOptions.ConnectionString = HOW TO GET THE MONGO DB CONNECTION STRING HERE });
But I'm not sure how I can retrieve my instance of IMongoDbSettings.
Just to be clear, I know that I can do a configuration.GetSection("MongoDbSettings") and then access GetSection("username"), but here my goal is to get my instance of IMongoDbSettings

Swagger-net breaks when using [FromUri] with a complex EF model

I'm using Swagger-Net in my .NET 4.5.1 WebAPI project and one of my API calls is causing the Swagger UI to spin forever on load before coming back with the error below.
Specifically, I found that using [FromUri] in combination with a complex EF entity that has references to other entities ends up causing this.
[HttpPost]
public APIResponse CreateSchool([FromUri]School school)
{
// save school object to db
}
public partial class School : IAuditableEntity,IEntity
{
public School()
{
this.Affiliations = new HashSet<Affiliation>();
this.SchoolAccreditations = new HashSet<SchoolAccreditation>();
this.SchoolAdultRoles = new HashSet<SchoolAdultRole>();
this.SchoolCareOptions = new HashSet<SchoolCareOption>();
this.SchoolDailySessions = new HashSet<SchoolDailySession>();
this.SchoolEligibilityRequirements = new HashSet<SchoolEligibilityRequirement>();
// ...more hashsets
[DataMember]
public int SchoolID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public bool Active { get; set; }
//...more properties
}
}
Is there a way to still use FromUri and the EF model? Or do I need to change my API call signature?

Entity Framework 6 Programmatically Connect to Postgres

I'm working on programmatically establishing a connection to PostgresSQL using Entity Framework 6. I have this class:
public class ClearspanDatabaseContext : DbContext
with this constructor:
public ClearspanDatabaseContext()
: base(buildConnectionString())
{
}
Here's the static method that makes the connection string programmatically:
private static string buildConnectionString()
{
RegisterDbProvider("Npgsql", ".Net Framework Data Provider for Postgresql", "Npgsql Data Provider", "Npgsql.NpgsqlFactory, Npgsql");
EntityConnectionStringBuilder entityConnectionStringBuilder = new EntityConnectionStringBuilder();
entityConnectionStringBuilder.Provider = "Npgsql";
entityConnectionStringBuilder.ProviderConnectionString = "host=192.168.168.140;Port=5432;username=ClearspanDevLogin;password=*******;database=ClearspanWebServerDev";
return entityConnectionStringBuilder.ToString();
}
And here's the method that registers Npgsql as a database provider, taken from this source:
public static bool RegisterDbProvider(string invariant, string description, string name, string type)
{
try
{
DataSet ds = ConfigurationManager.GetSection("system.data") as DataSet;
foreach (DataRow row in ds.Tables[0].Rows)
{
if (row["InvariantName"].ToString() == invariant)
{
return true;
}
}
ds.Tables[0].Rows.Add(name, description, invariant, type);
return true;
}
catch
{
}
return false;
}
This generates a string like this:
"provider=Npgsql;provider connection string=\"host=192.168.168.140;Port=5432;username=ClearspanDevLogin;password=********;database=ClearspanWebServerDev\""
But I get an ArgumentException:
Keyword not supported: 'provider'.
I think I am close to the programmatic connection, but am missing something small. What can I do to resolve this exception and properly setup this connection programmatically? No app.config answers, I'm working in a class library, which ignores app.config (see the comments of the accepted answer to this question). This program must remain this way because it is used as a plugin - it does not (nor should it) run on its own. Thanks in advance.
Ok, here is working example for you which I verified is working.
Using dummy code-first EF 6 model + custom DbConfiguration class:
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
}
[DbConfigurationType(typeof (NpgsqlConfiguration))]
public class SchoolContext : DbContext {
public SchoolContext(string cs) : base(cs) {
}
public DbSet<Enrollment> Enrollments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
}
}
class NpgsqlConfiguration : System.Data.Entity.DbConfiguration
{
public NpgsqlConfiguration()
{
SetProviderServices("Npgsql", Npgsql.NpgsqlServices.Instance);
SetProviderFactory("Npgsql", Npgsql.NpgsqlFactory.Instance);
SetDefaultConnectionFactory(new Npgsql.NpgsqlConnectionFactory());
}
}
Then, instead of your buildConnectionString(), just pass postgre connection string in constructor:
using (var ctx = new SchoolContext("host=192.168.168.40;port=5432;...")) {
Console.WriteLine(ctx.Enrollments.ToArray());
}
And that is all. Config file is completely empty during that, and it works.
Have you looked at Code-Based Configuration? Create a DbConfiguration class with a public parameterless constructor in the same assembly as your DbContext
class MyConfiguration : System.Data.Entity.DbConfiguration
{
public MyConfiguration()
{
SetProviderServices("Npgsql", Npgsql.NpgsqlServices.Instance);
SetProviderFactory("Npgsql", Npgsql.NpgsqlFactory.Instance);
}
}
Now I think the DbContext should use that provider factory by default, and you can construct the DbContext with just the connection string. But if it's in a different assembly, then you have a bit more work to do, but that can be found in the link above.
A potential problem with the above solution is that any configuration in the config file will take precedence, so maybe it would be safer to use the option described in here:
var conn = DbProviderFactories.GetFactory("MY_CONN_PROVIDER").CreateConnection();
conn.ConnectionString = "MY_CONN_STR";
new DbContext(conn, true);
where your provider is "Npgsql", which was registered in RegisterDbProvider above.
Also see https://msdn.microsoft.com/en-us/library/dd0w4a2z(v=vs.110).aspx

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.