0

I am working on a Winforms project, and I am just setting up the setup file for the installation of the program.

Scenario

The connection string I have set for my use is like this:

 SqlConnection con = new SqlConnection(@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=F:\Application\MyAppv1.0\MyApp\DB.mdf;Integrated Security=True");
 return con;

Here, I use local DB from my personal location.

Question

On installation on the client's PC, the database is also attached, so the installed files will be on C:\Program Files\Author\MyAppv1.0. When I use the same connection string, the app shows an exception. So, should I update my connection string for that location during the setup creation? (I am using MSI).

Is there any commonly followed approach for this scenario?

My aim is to make the installed app use the DB that is also on the same location of installation named DB.mdf and is provided with setup.

Thanks guys in advance.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Opus Corpus
  • 115
  • 1
  • 8
  • You should attach the DB properly, then set the actual database name in your connection string. See [what's the issue with AttachDbFilename](https://stackoverflow.com/questions/11178720/whats-the-issue-with-attachdbfilename) Even LocalDB allows attaching a database properly, use `CREATE DATABASE ... FOR ATTACH` – Charlieface Dec 12 '21 at 03:17
  • Put the connection strings in a config file. Use config transformations to change the setting in non-local builds/deployments. – Flydog57 Dec 12 '21 at 04:32
  • this is how I set the connection settings ` ` Still Not working after installation.. cannot access DB is the exception. @Charlieface, @Flydog57 – Opus Corpus Dec 12 '21 at 05:06
  • What actual name (not filename) did you give the DB when you attached it? `DB.mdf` is an odd name for an attached database, you would have needed to quote it `CREATE DATABASE [DB.mdf]...` – Charlieface Dec 12 '21 at 05:13
  • Actually, it is `MyAppDB` is the name of the database. Whether we have to create a database again with CREATE Query?. I have all set up with the database. @Charlieface – Opus Corpus Dec 12 '21 at 06:03
  • Then you should have `Data Source=MyAppDB` – Charlieface Dec 12 '21 at 06:32
  • Yeah, That's what I coded but it is not working (not connecting to DB). @Charlieface – Opus Corpus Dec 12 '21 at 07:51
  • Did you create the database using `CREATE DATABASE MyAppDB ... FOR ATTACH`? Did you do it in SSMS while connected to LocalDb? Did you remove `AttachDbFilename=...` from your connection string? (should now be just `Server=(LocalDB)\MSSQLLocalDB;Data Source=MyAppDB;Integrated Security=True");`) – Charlieface Dec 12 '21 at 07:54
  • You have to add a method inside of your program when it starts, and check it every time. In this method, check if database exists near your exe, if exists, do nothing, else if database file do not exists, create a bunch of scripts to generate database and all tables and default data, and call these scripts through your c# program. Remember, these scripts for creating database can be automatically generated by SQL server, just by several simple clicks. – Reza Akraminejad Dec 12 '21 at 08:06
  • I did the same thing, but not working on debugging mode itself but if I provide the entire full location, it works => `F:\Application\MyAppv1.0\MyApp\MyAppDB.mdf `, But it should not be the case for client right? the connection string should be dynamic. @Charlieface – Opus Corpus Dec 12 '21 at 10:09
  • Even then, We have to connect through the database using a connection string, which location can we provide to adjust the connection string if the user chooses and changes the location of the database ? @Hamed_gibago – Opus Corpus Dec 12 '21 at 10:10
  • You shouldn't need to specify the location except at setup., when you run `CREATE DATABASE`. Normally you would just connect with the database name. Yes, you could have the user supply a database name, even a server name. Do *not* use `AttachDbFilename` – Charlieface Dec 12 '21 at 12:39
  • Do you mean, you want to create the DB programmatically using C# and get the location from the user to access it from my application all at the start of my application?. Can I connect to the DB without using these techniques? like attaching the DB along with all files in setup and somehow connecting the DB and using just like we do on already created database and tables? – Opus Corpus Dec 12 '21 at 13:52
  • I want to attach an already created DB with tables and values into the setup with the application and allow my app to use in which should be available on the application installed folder. The client pc has no SSMS and stuff... It is clean windows 11. is that possible?...attaching DB and application with believing it will connect with the same DB I created to work after installation? – Opus Corpus Dec 12 '21 at 14:12
  • You don't have to install `SSMS` in client computer, nor do you need do setting during installation. For creating database during installation, you have to work with visual studio setup project or installsheild, which I had worked with both of them, they are really like pain in back, you don't need them for this purpose. Just create a method at beginning of program and check db. For path of installed location, just use `reflection.assembly.getexecutingAssembly` if I'm not mistaken (see Microsoft docs) to get executing file and then get it's folder to check if db exists or not, and do the rest. – Reza Akraminejad Dec 12 '21 at 18:12
  • Thanks, guys @Charlieface and Hamed_gibago . Just post it on the answer and I will mark it as the answer. – Opus Corpus Dec 13 '21 at 01:29

1 Answers1

1

Do not use AttachDbFilename, it has many issues. Instead, attach your database normally using CREATE DATABASE...FOR ATTACH.

At startup of your app, you can connect to the server using master as the current DB, and check for existence of your DB. If it's not there you can create it.

private static void CheckDbExistence(string connectionString)
{
    const string query = @"
IF NOT EXISTS (SELECT 1
    FROM sys.databases
    WHERE name = 'MyDb')
BEGIN

    DECLARE @sql nvarchar(max) = N'
CREATE DATABASE MyDb ON
  (FILENAME = ' + QUOTENAME(@mdf, '''') + '),   
  (FILENAME = ' + QUOTENAME(@ldf, '''') + ')
  FOR ATTACH;
';

    EXEC (@sql);
END;
    ";
    var csb = new SqlConnectionStringBuilder(connectionString);
    csb.Initial Catalog = "master";
    using (var conn = new SqlConnection(csb.ConnectionString))
    using (var comm = new SqlCommand(query, conn))
    {
        comm.Parameters.Add("@mdf", SqlDbType.NVarChar, 255).Value = Path.Combine(Environment.CurrentDirectory, "MyDb.mdf");
        comm.Parameters.Add("@ldf", SqlDbType.NVarChar, 255).Value = Path.Combine(Environment.CurrentDirectory, "MyDb.ldf");
        conn.Open();
        comm.ExecuteNonQuery();
    }
}
Charlieface
  • 52,284
  • 6
  • 19
  • 43
  • Then What about the tables and stored procedures that I want to create on the LocalDB? – Opus Corpus Dec 14 '21 at 03:27
  • That would be stored in the `.mdf` file and `.ldf` log file, you are just attaching an existing database – Charlieface Dec 14 '21 at 10:43
  • I get incorrect syntax near 'FOR'. and What Connection string should I mention at initial stage? is this the correct one => `Server=localhost;Integrated security=SSPI;database=master` – Opus Corpus Dec 15 '21 at 01:41
  • Sorry got the syntax off a bit, and looks like `CREATE DATABASE` cannot be parameterized so need to use dynamic SQL. The business with `csb.Initial Catalog = "master";` was so that you could keep the connection string the same, but just change the database before connecting. So you can use `database=MyDB` and this code will switch to `master` to connect – Charlieface Dec 15 '21 at 01:59
  • Dynamic SQL Like this => `str = "CREATE DATABASE MyDB ON PRIMARY " + "(NAME = MyDB_Data, " + "FILENAME = 'C:\\MyDB.mdf', " + "SIZE = 2MB, MAXSIZE = 10MB, FILEGROWTH = 10%)" + "LOG ON (NAME = MyDB_Log, " + "FILENAME = 'C:\\MyDB.ldf', " + "SIZE = 1MB, " + "MAXSIZE = 5MB, " + "FILEGROWTH = 10%)"; SqlCommand myCommand = new SqlCommand(str, myConn); myConn.Open(); myCommand.ExecuteNonQuery(); ` – Opus Corpus Dec 15 '21 at 02:46
  • Dude... It's Not even connecting to any database. I used this ` ` And Cannot connect to any database and getting exception of `error: 40 - Could not open a connection to the SQL Server` – Opus Corpus Dec 15 '21 at 02:54
  • If you are free we can connect in some conferencing app. Because this is a simple topic for you to finish and I am over this for more than 2 weeks. Help me with this, please. – Opus Corpus Dec 15 '21 at 02:56
  • I'd expect a connection string something like `Data Source=YourServer;Initial Catalog=MyDB;Integrated Security=True` and `YourServer` would be `.` for the localhost, or the DNS or IP address of a remote server, or `(LocalDB)\MSSQLLocalDB` for LocalDB. And `MyDB` is the *database name* you gave for `CREATE DATABASE` not the filename – Charlieface Dec 15 '21 at 11:35