EF, Code First, how to initialize database on a specific location (HDD) - database

does anybody know how to spedify exact .mdf/.log file location during EF CodeFirst database initialization?
For a debug and testing scenario (but specifying exact DB files location can be useful in production as well), I'd like to re-deploy database during application start-up, but also I'd like to create DB files on a specific location (e.g. secong hard drive).
public class MyCustomInitialized : DropCreateDatabaseAlways<MyContext>
{
public override void InitializeDatabase(MyContext context)
{
if (context.Database.Exists())
{
// set the database to SINGLE_USER so it can be dropped
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
// drop the database
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
// Doesn't work yet
var directoryPath = ConfigurationManager.AppSettings["DatabaseDirectoryPath"];
var fileName = ConfigurationManager.AppSettings["DatabaseFileName"];
if(!Database.Exists()) {
var qry = string.Format(
"USE master CREATE DATABASE {0}" + Environment.NewLine +
"ON PRIMARY" + Environment.NewLine +
"( NAME = {0}, FILENAME = '{1}')" + Environment.NewLine +
"LOG ON" + Environment.NewLine +
"( NAME = {2}, FILENAME = '{3}')" + Environment.NewLine
, this.Database.Connection.Database,
Path.Combine(directoryPath, fileName + ".mdf"),
this.Database.Connection.Database + "_log",
Path.Combine(directoryPath, fileName + "_log.ldf"));
// -- EXCEPTION HERE,
Database.ExecuteSqlCommand(qry);
Database.ExecuteSqlCommand("USE " + this.Database.Connection.Database);
}
base.InitializeDatabase(context);
}
}
The exeption I get:
Cannot open database "DatabaseName" requested by the login. The login
failed. Login failed for user 'SomeUser'. A severe error occurred on
the current command. The results, if any, should be discarded.
If the database can be created by EF during initialization, how this initialization can be overriden?
Thanks,
Tom

I was able to get the below working, in both the database exists and non-exists scenarios, however, there is one issue in that the Code First table creation isn't being triggered (i.e. this is only a partial solution - there is still a step needed to actually get EF to create the Code First tables).
(My context was called Model1)
public class MyCustomInitialized : DropCreateDatabaseAlways<Model1>
{
public override void InitializeDatabase(Model1 context)
{
if (context.Database.Exists())
{
// set the database to SINGLE_USER so it can be dropped
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,
"ALTER DATABASE [" + context.Database.Connection.Database +
"] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
// drop the database
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,
"USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
}
var directoryPath = #"c:\temp";
var fileName = "Foo";
var qry = string.Format(
"USE master CREATE DATABASE {0}" + Environment.NewLine +
"ON PRIMARY" + Environment.NewLine +
"( NAME = {0}, FILENAME = '{1}')" + Environment.NewLine +
"LOG ON" + Environment.NewLine +
"( NAME = {2}, FILENAME = '{3}')" + Environment.NewLine
, context.Database.Connection.Database,
Path.Combine(directoryPath, fileName + ".mdf"),
context.Database.Connection.Database + "_log",
Path.Combine(directoryPath, fileName + "_log.ldf"));
using (var conn = new SqlConnection(#"data source=.\SQLExpress;initial catalog=master;integrated security=True;"))
using (var cmd = new SqlCommand(qry, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
-- TODO trigger the table creation
this.Seed(context);
context.SaveChanges();
}
}
Some notes:
Database belongs to the context
You won't be able to recreate the database on the Context connection, since when you drop the database, the Initial Catalog in your EF connection string will have disappeared. I've just used a new Ado Connection to do the Drop, else "Cannot open database \"FOO\" requested by the login". I would also consider moving the DROP of the Context connection into a master connection.
Calling
base.InitializeDatabase(context);
Causes the Db to be dropped and recreated because of the DropCreateDatabaseAlways strategy which includes:
context.Database.Delete();
context.Database.Create(DatabaseExistenceState.DoesNotExist);
So hence
-- missing something here, viz creating the tables
this.Seed(context);
context.SaveChanges();

Related

Adding a Database User for each Customer

I'm creating a database that has two main parts: a front end which the customer sees and a backend that only the company can see.
It is an email subscriber system so I want the customer to be able to view, add, edit and delete their entries in the email subscriber table, but all the admin-related tables should be hidden from them.
As I'm fairly new to SQL Server 2017, I'm still getting my head around logins, users and roles.
The main question I wanted to ask is what is the best way of doing this? I know I can manually set up database users and give them grant/deny permissions, but how do I do this automatically so that every time a customer's details are added to a new row in the customer table, a new database user in the sidebar is added.
Try this
public static void AddUsersToDatabase(string databaseserver, string databasename, string usertobeadded)
{
using (SqlConnection conn = new SqlConnection("server=" + databaseserver + "; database=" + databasename + "; User ID=WPDOMAIN\\spdev; Integrated Security=SSPI; password=Password123;"))
{
conn.Open();
string password = "Password123";
string sql = "CREATE LOGIN " + usertobeadded + " WITH PASSWORD = '" +
password + "'; USE " + databasename + "; CREATE USER " + usertobeadded + " FOR LOGIN " + usertobeadded + ";";
SqlCommand cmd = new SqlCommand(sql);
cmd.ExecuteNonQuery();
conn.Close();
}
}

data always getting from the previous databse not from the new database

I am facing an issue from sql server that
SqlDataAdapter sda = new SqlDataAdapter(
"Select Role from Login where username ='" + textBox1.Text + "' and password '" + textBox2.Text + "' ",
con);
My sql command always get data from the pervious database not from the new one.
Your connection(con) is pointing to your old database change it to your new database.

How to create a Database user in Entity Framework

Been working on my first Entity Framework project. As part of the project I am going to be creating a number of SSRS reports. In order to connect to the database I need to have a Reports user that will only access to the specific database on the server. In the past i have always written a script to add Database users but I want to know is there a way that i can do this using Entity Framework instead?
Assuming your user already has a login defined at the SQL Server level (Security > Logins), you can call the following method from your DB initializer seed method to add the user to the database:
private void AddDbUser(MyDataContext myDB)
{
string accountDomainName = "AccountDomainName"; // replace with user's login domain
string accountLoginID = "AccountLoginID"; // replace with user's login ID
string sql =
"USE [MyDB]" +
"CREATE USER [MyNewUser] FOR LOGIN [" + accountDomainName + "\\" + accountLoginID + "]" +
"ALTER AUTHORIZATION ON SCHEMA::[db_datareader] TO [" + accountLoginID + "]" +
"ALTER AUTHORIZATION ON SCHEMA::[db_datawriter] TO [" + accountLoginID + "]" +
"EXEC sp_addrolemember N'db_datawriter', N'" + accountLoginID + "'" +
"EXEC sp_addrolemember N'db_datareader', N'" + accountLoginID + "'";
myDB.Database.ExecuteSqlCommand(sql);
}
The exact SQL needed is dependent on your configuration. To have SQL Server generate the SQL for your scenario, you could open the add user dialog in SSMS (Database > Users > New User...), fill out the fields, and click the "Script" button at the top instead of hitting OK at the bottom. Note that any "GO" lines will need to be removed from the generated script before pasting it into the method above.
You would need to tell EF to use the appropriate stored procedures to do so. You could also wrap these up in a sproc of your own that wraps the relevant commands. There is no native "CreateReportsUser" type method within EF that I know of.
Edit: I probably should have provided this reference to be a "complete" answer. Apologies.
Here's how you can do what I recommend: How to call Stored Procedure in Entity Framework 6 (Code-First)?

Insert into RemoveFile table in MSI

In order to automate some actions in MSI I have been trying to insert into RemoveFile table using JScript and keep getting errors and since there is not much error description i am not able to figure out the issue in query and the only error that i get when i try to debug using csript is -2147467259 OpenView,SQL,
This is the query that i am using to insert into removefile table, Can anyone please help me figuring out the issue.
"INSERT INTO `RemoveFile` (`FileKey`, `Component_`, `FileName`, `DirProperty`, `InstallMode`) VALUES (`_142D31F52C744D6FB945F01BA06EEFB3`, `C__931358B017AE83C769F5CB9E95BD2401`, `Product version 2.0.lnk`, `DesktopFolder`, 1)
Have you opened the view on the installer database?
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(<your-product.msi>,
msiOpenDatabaseModeTransact);
sql = "INSERT INTO `RemoveFile` "
+ "(`FileKey`, `Component_`, `FileName`, "
+ "`DirProperty`, `InstallMode`) "
+ "VALUES ('_142D31F52C744D6FB945F01BA06EEFB3', "
+ "'C__931358B017AE83C769F5CB9E95BD2401', "
+ "'Product version 2.0.lnk', 'DesktopFolder', 1)";
view = database.OpenView(sql);
view.Execute();
view.Close();

DbCommand can't run multiple SQL command in one ExecuteNonQuery()

Hello I have the following problem and I can't solve it.
With DbCommand I'm trying execute this SQL statement
Dim strCommnad As String =
"CREATE DEFAULT [dbo].[DOMAIN_XLibPKID_D] AS (0);" + Environment.NewLine +
"CREATE TYPE [dbo].[XLibPKID] FROM BIGINT NOT NULL;" + Environment.NewLine +
"EXEC sp_bindefault 'DOMAIN_XLibPKID_D', 'XLibPKID';"
command.CommandText = strCommnad
command.CommandType = CommandType.Text
command.ExecuteNonQuery()
but I always get this an error message
Incorrect syntax near the keyword 'CREATE'.
But when I run each command from strCommand standalone then everything works fine.
I'm using VS 2010 Professional and SQL Server 2008 R2 Express.
Thanks for any help.
I'm not entirely sure what you're trying to do - but your approach seems overly complicated ...
You appear to be adding a DEFAULT clause to your XLibPKID column - right? This ALTER TABLE statement should do that, too:
command.CommandText =
"ALTER TABLE [dbo].[DOMAIN_XLibPKID_D] " +
" ADD CONSTRAINT DF_XLibPKID DEFAULT (0) FOR XLibPKID";
command.ExecuteNonQuery()
This just adds a separate DEFAULT CONSTRAINT to your table.
Try adding a GO between each statement:
Dim strCommnad As String = "CREATE DEFAULT [dbo].[DOMAIN_XLibPKID_D] AS (0);" + Environment.NewLine +
"GO; CREATE TYPE [dbo].[XLibPKID] FROM BIGINT NOT NULL;" + Environment.NewLine +
"GO; EXEC sp_bindefault 'DOMAIN_XLibPKID_D', 'XLibPKID';"

Resources