How do I tell EF what to name the database and where to put it?
If there is no connection string in the Web.Config, it tries to put it in the local SQLEXPRESS Server, but I want to put it out on a known SQL Server and name it what I want. Any suggestions?
Create a connection string in the app.config/web.config with the same name as the context and the EF will use that DB.
How to Use a Different Connection String Name with EF
EF will use the name of the database in the connection string. When you want to decouple the name of your connection string from EF, you need to provide your connection string to the constructor. Example:
public class DatabaseContext : DbContext
{
public DatabaseContext()
: base(ApplicationParameters.ConnectionStringName)
{
}
public DatabaseContext(string connectionStringName)
: base(connectionStringName)
{
}
}
in Class :
public class Context : DbContext
{
//SET CONNECTION STRING NAME FOR DataBase Name :
public Context() : base("YourConnectionName") { }
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
in web.config:
<connectionStrings>
<add name="YourConnectionName" connectionString="Data Source=A-PC\SQLEXPRESS;
Initial Catalog=MyDataBase; Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
Thanks ferventcoder.
Ref => http://brandonclapp.com/connection-strings-with-entity-framework-5-code-first/
Alternatively you can set the name in your DbContext constructor.
As already mentioned, you can declare your connection string inside the config file of your application with a name (let's say "YourDBName") and then pass this to the DbContext base constructor call (I will add this to the answer for providing a complete answer - great answers already given on this).
Alternatively, you can set this programmatically in your DbContext Extension class, using the Database.Connection.ConnectionString property. For instance:
App.config:
<!-- More.... -->
<!-- You can do this in a declarative way -->
<connectionStrings>
<add name="YourDBName"
connectionString="<Your connection string here>"
providerName="<Your provider here>" />
</connectionStrings>
<!-- More.... -->
DatabaseContext.cs:
public class DatabaseContext : DbContext
//Link it with your config file
public DatabaseContext () : base("YourDBName")
{
//And/Or you can do this programmatically.
this.Database.Connection.ConnectionString = "<Your Connection String Here>";
// More Stuff.....
}
}
If you point your connection-string at an existing database then EF “code first” will not try and create one automatically.
EF “code first” uses a convention where context classes by default look for a connection-string that has the same name as the context class.
Using ef code first with an existing database
For reference, here is how to do it in code using VB.NET:
Public Class DatabaseContext : Inherits DbContext
Public Property Users As DbSet(Of User)
Public Sub New()
MyBase.New("NewFileName.sdf")
End Sub
End Class
You can specify the name of the connection string the context constructor:
public YourDbContext()
: base("Name=YourDbContext")
{
}
Related
Just starting playing with the .Net Core RC2 by migrating a current MVC .Net app I developed. It looks like to me because of the way that configuration is handled with appsettings.json that if I have multiple connection strings I either have to use EF to retrieve a connectionstring or I have to create separate classes named for each connection string. All the examples I see either use EF (which doesn't make sense for me since I will be using Dapper) or the example builds a class named after the section in the config. Am I missing a better solution?
"Data": {
"Server1": {
"ConnectionString": "data source={server1};initial catalog=master;integrated security=True;"
},
"Server2": {
"ConnectionString": "data source={server2};initial catalog=master;integrated security=True;"
}
}
Why would I want to build two classes, one named "Server1" and another "Server2" if the only property each had was a connectionstring?
There are a couple of corrections that I made to Adem's response to work with RC2, so I figured I better post them.
I configured the appsettings.json and created a class like Adem's
{
"ConnectionStrings": {
"DefaultConnectionString": "Default",
"CustomConnectionString": "Custom"
}
}
and
public class ConnectionStrings
{
public string DefaultConnectionString { get; set; }
public string CustomConnectionString { get; set; }
}
most of Adem's code comes out of the box in VS for RC2, so I just added the line below to the ConfigureServices method
services.Configure<Models.ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
The main missing point is that the connection string has to be passed to the controller (Once you’ve specified a strongly-typed configuration object and added it to the services collection, you can request it from any Controller or Action method by requesting an instance of IOptions, https://docs.asp.net/en/latest/mvc/controllers/dependency-injection.html)
So this goes to the controller,
private readonly ConnectionStrings _connectionStrings;
public HomeController(IOptions<ConnectionStrings> connectionStrings)
{
_connectionStrings = connectionStrings.Value;
}
and then when you instantiate the DAL you pass the appropriate connectionString
DAL.DataMethods dm = new DAL.DataMethods(_connectionStrings.CustomConnectionString);
All the examples show this, they just don't state it, why my attempts to pull directly from the DAL didn't work
I don't like the idea of instantiating the DAL. Rather, I'd do something like this
public class ConnectionStrings : Dictionary<string, string> { }
And something like this in the ctor of the DAL
public Dal(IOptionsMonitor<ConnectionStrings> optionsAccessor, ILogger<Dal> logger)
{
_connections = optionsAccessor.CurrentValue;
_logger = logger;
}
and you'll need to register with IoC
services.Configure<ConnectionStrings>(configuration.GetSection("ConnectionStrings")); /* services is the IServiceCollection */
Now you have all the connection strings in the DAL object. You can use them on each query or even select it by index on every call.
You can use Options to access in DAL layer. I will try to write simple example(RC1):
First you need to create appsettings.json file with below content:
{
"ConnectionStrings": {
"DefaultConnectionString": "Default",
"CustomConnectionString": "Custom"
}
}
Then create a class:
public class ConnectionStrings
{
public string DefaultConnectionString { get; set; }
public string CustomConnectionString { get; set; }
}
And in Startup.cs
private IConfiguration Configuration;
public Startup(IApplicationEnvironment app)
{
var builder = new ConfigurationBuilder()
.SetBasePath(app.ApplicationBasePath)
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
// ....
services.AddOptions();
services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
}
Finally inject it in the DAL class:
private IOptions<ConnectionStrings> _connectionStrings;
public DalClass(IOptions<ConnectionStrings> connectionStrings)
{
_connectionStrings = connectionStrings;
}
//use it
As I understand a connection string is attached to one class only. But what if I have many Model classes? Can I use one connection string for multiple classes?
This is a simple version of my UserModel.cs file:
public class UserModel
{
public int Id { get; set; }
public string Email { get; set; }
}
public class UserTable : DbContext
{
public UserModel GetByEmail(string Email)
{
return this.Database.SqlQuery<UserModel>("SELECT * FROM Users WHERE Email=#Email", new SqlParameter("Email", Email)).SingleOrDefault();
}
}
And this is the connection string:
<connectionStrings>
<add name="UserModel"
connectionString="Server=.\SQLEXPRESS;Database=MyDatabase;User Id=MyUser;Password=MyPassword;"
providerName="System.Data.SqlClient" />
</connectionStrings>
Now lets say I want to add a new Model class named DataTable also derived from DbContext as user table is. Do I need a connection string named the same or can I use the already defined one? What is the conventional way of dealing with multiple Model classes and connection strings?
The DbContext class uses the ConnectionString to make the connection to the database.
You normally have multiple model classes exposed by a DbContext.
It is possible to have multiple DbContext objects that use the same connection string value to connect to the database. In this way, you can separate portions of your model into separate contexts if desired (for example, if you are creating separate assemblies that access different tables but provide similar services to the application).
One caveat to note with EF up to at least 5.0, you cannot use the code-first migrations with multiple DbContexts, one will overwrite the other's changes. The solution to this is to create an aggregated DbContext that is only used for the Migrations process.
I've done this in an app that I built. I used the Unity IoC container, and the built a Plugin Interface that allowed me to pass my ConnectionStringName into my separated DbContexts. An example of the plugin in one of the assemblies was:
public class Bootstrapper : IBootstrapper
{
public void Bootstrap(IUnityContainer container, string connectionStringName)
{
container.RegisterType<ISQService, SQService>();
container.RegisterType<ISQEntities, SQEntities>(
new HierarchicalLifetimeManager(), new InjectionConstructor(connectionStringName));
container.RegisterType<IController, SQController>("SQ");
}
}
My global.asax referenced the bootstrapper class below:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders[typeof(DataTable)] = new DataTableModelBinder();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Bootstrapper.Initialise();
}
protected void Application_End()
{
Bootstrapper.Dispose();
}
Bootstrapper
public static class Bootstrapper
{
private static IUnityContainer container;
public static void Initialise()
{
container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
public static void Dispose()
{
container.Dispose();
}
private static void RegisterPlugins(IUnityContainer theContainer, string wildcard, string connectionStringName)
{
var pluginBootStrappers = from Assembly assembly in wildcard.LoadAssemblies()
from type in assembly.GetExportedTypes()
where typeof(IBootstrapper).IsAssignableFrom(type)
select (IBootstrapper)Activator.CreateInstance(type);
pluginBootStrappers.ToList().ForEach(b => b.Bootstrap(theContainer, connectionStringName));
}
private static IUnityContainer BuildUnityContainer()
{
var theContainer = new UnityContainer();
const string ConnectionStringName = "MyDb";
RegisterPlugins(theContainer, "MyApp.Systems.*.dll", ConnectionStringName);
// Register Application Specific objects
theContainer.RegisterType<IMyEntities, MyEntities>(
new HierarchicalLifetimeManager(),
new InjectionConstructor(ConnectionStringName));
theContainer.RegisterType<IAimaService, AimaService>();
var factory = new UnityControllerFactory(theContainer);
ControllerBuilder.Current.SetControllerFactory(factory);
return theContainer;
}
}
The connection string defines the parameters needed to connect to the DB.
Maybe I think you are talking about or confusing the SQL Query with the connectionstring.
Yes one SQL Query can QUERY more than one table at any given time.
Maybe you could look into the "SQL Query Statement" on google for in depth information.
Ok so here's some context: I'm using EF5, MVC4 and SQL CE4 to build up a web application. I've been loosely following this tutorial with a few differences.
My context class and POCO objects are in their own assembly.
I'm using SQL CE4 instead of SQL Express Local DB
My classes aren't as simple as the tutorial
I've already used a workaround to get simple classes to work register.
I had thought using enums in EF5 was supported in EF5, but can they be used in Keys?
When I try to add a control (Add Controller, MVC controller with read/write actions and views, using Entity Framework) for a simple class (1 int key property, 1 string property), it works.
I get varied errors when trying to add a class that has a property which is part of a key (primary or foreign)
Unable to retrieve metadata for 'blah'. Using the
same DbCompiledModel to create contexts against different types of
database servers is not supported. Instead, create a separate
DbCompiledModel for each type of server being used.
Index was out of range. Must be non-negative and less than the size of
the collection.
Parameter name: index
C:\Program Files (x86)\Microsoft Visual Studio\11.0\Common7\IDE\ItemTemplates\CSharp\Web\MVC 4\
CodeTemplates\AddController\ControllerWithContext.tt(0,0) : error :
Running transformation: System.IndexOutOfRangeException: Index was outside the bounds of the
array.
---StackTrace---
The only similarities I've found between these classes is that they have an emun that's tied to a key. Other classes with non-key enums generate correctly. Is this the issue or have I completely missed the mark?
Edit: Example of a class which fails
public class A
{
public virtual AIdEnum Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<B> Bs { get; set; }
public virtual ICollection<C> Cs { get; set; }
}
Ok, so I've just ran this up quickly with SQL CE 4 and it appears to work great:
public class EnumTestContext : DbContext
{
public EnumTestContext() : base("CEDB")
{
}
public DbSet<MyClass> MyClasses { get; set; }
}
public enum MyEnum
{
EnumValue1,
EnumValue2
}
public class MyClass
{
[Key, Column(Order = 0)]
public MyEnum MyEnumKey { get; set; }
[Key, Column(Order = 1)]
public int MyIntKey { get; set; }
[Column(Order = 2)]
public string Name { get; set; }
}
I then add an entity like this:
using (var context = new EnumTestContext())
{
context.MyClasses.Add(new MyClass()
{
MyEnumKey = MyEnum.EnumValue1,
MyIntKey = 22,
Name = "Hello World"
});
context.SaveChanges();
}
This is all working fine for me - does this help?
You need put this line:
Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
before the DbContext lifecicle beggin.
A exemple that you can to download in the MSDN Gallery
It seems my issue is that Controller creation doesn't work with SQLCE 4.0 connectionStrings so using a conectionString of provider of System.Data.SqlClient handled that issue.
The next problem I had was that connectionString values (such as encryption) were not respected through this means so I now have 2 different constructors to get around this bug.
#if DEBUG
public Context()
: base("name=DefaultConnection")
{ ; }
#else
/// <summary>
/// Default Constructor
/// </summary>
public Context()
: base("name=CompactConnection")
{ ; }
#endif
Here's my configuration:
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
<connectionStrings>
<add name="CompactConnection" providerName="System.Data.SqlServerCe.4.0"
connectionString="Data Source="|DataDirectory|\DB.sdf";encryption mode=platform default;password="P4$$w0rd!""/>
<add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-MsSqlCe-20121028004432;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-MsSqlCe-20121028004432.mdf" />
</connectionStrings>
Of course, this is just a workaround for a deeper issue. If anyone else knows of the root cause of this issue, I'd love to know.
According to this article description custom-membership-provider-with-repository-injection
I implement the custom Membership provide with inject.
Custom Membership provider
using Ninject;
public class CustomMembershipProvider : MembershipProvider
{
[Inject]
public IUserRepository UserRepository { get; set; }
[...]
Custom Role Provider
using Ninject;
public class CustomRoleProvider : RoleProvider
{
[Inject]
public IUserRoleRepository UserRoleRepository { get; set; }
[...]
within Web.Config
<membership defaultProvider="CustomsMembershipProvider">
<providers>
<clear/>
<add name="CustomsMembershipProvider" type="namespace.CustomsMembershipProvider"/>
</providers>
</membership>
<roleManager enabled="true" defaultProvider="customRoleProvider">
<providers>
<clear/>
<add name="customRoleProvider" type="namespace.customRoleProvider"/>
</providers>
</roleManager>
Now within NinjectWebCommon
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
[...]
kernel.Bind<IUserRepository>().To<UserRepository>();
kernel.Bind<IUserRoleRepository>().To<UserRoleRepository>();
// Inject user & role repository into our custom membership & role providers.
kernel.Inject(Membership.Provider);
kernel.Inject(Roles.Provider);
}
when I run application I got error
This method cannot be called during the application's pre-start
initialization stage.
from kernel.Inject(Membership.Provider); this line
But If I Kernel setting put within Application_Start
I got bellow Error
Error activating IUserRepository No matching bindings are available,
and the type is not self-bindable. Activation path: 2) Injection of
dependency IUserRepository into property UserRepository of type
CustomMembershipProvider 1) Request for CustomeMembershipProvider
How to solve that. ??
The result is always null. why? because asp.net has it's own static property for membership.
which is membership.provider. and this instance is not part of instance ninject management.
to workaround it , you need to use kernel.inject . but on the generate aspnetmvc.cs you would see that it's injection on PreApplicationStart event and won't let you.
here is the soloution by cipto that solve the problem for me. add this to your NinjectWebCommon
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
}
Link to article: Ninject and customMembership asp.net mvc 3
I had a lot of trouble trying this and ended up adding a method that gets me a repository
using System.Web.Mvc; //Used to access dependency resolver
private IUserRepository GetUserRepository()
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
I then call this in the methods that require it
I was able to get the repository to become injected using constructor injection but as soon as I went to use the repository the object had been disposed. I found the above to be the simplest alternative.
However, I guess you could also use the Initialize() method
IUserRepository userRepository;
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
this.userRepository = DependencyResolver.Current.GetService<IUserRepository>();
}
Or another way would be to use a property
public IUserRepository UserRepository
{
get
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
}
Since a custom RoleProvider often comes along with the custom MembershipProvider, in that case it is useful to add an injection for the Role Provider class. I used the ramon22's solution with an additional line.
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
bootstrapper.Kernel.Inject(Roles.Provider);
}
I've created a controller factory and registered my types in code. I can do the following:
public class HomeController : Controller
{
public MasterEntities DbContext { get { return Container.Resolve<MasterEntities>(); }
}
public ActionResult Index()
{
//DbContext can be used here properly...
}
}
However I would like to have the property injected in the setter instead of having to call Container.Resolve<TypeName>() explicitly. Preferrable without using attributes or some configuration in code...
public MasterEntities DbContext { get; set; }
How can this be configured in my .config file? Or does this require the use of attributes or configuration in code?
<register type="HomeController">
<property name="DbContext" />
</register>
should do the trick.