3

I am using local database in my app and when I generate installation file (By Installer Package), after installing program it gives database path errors.

Eample

an attempt to attach an auto-named database for file....
//OR
The given path format is not supported

one

I've tried to edit database path in app.config file but it failed every time, By default my code line is like this:

<add name="SampleDatabaseWalkthrough.Properties.Settings.SampleDatabaseConnectionString"
            connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\SampleDatabase.mdf;Integrated Security=True"
            providerName="System.Data.SqlClient" />

And my app installing in C:\Program Files (86)\App_Folder\Setup Please note that future users might install it in custom path so I need a way to get dynamic path of installed app.

My question is How can I get app installed path to replace with this part AttachDbFilename=|DataDirectory|\SampleDatabase.mdf?

mafortis
  • 6,750
  • 23
  • 130
  • 288

2 Answers2

2

You could try to use AppDomain.CurrentDomain.SetData method to change your mdf file path.

Since, I don't know how do you published the winform project.

I recommend that you use Clickonce to publish it.

First, please include your mdf file in your project.

Second, you could try the following code to change the installed path after you published it.

 private void Form1_Load(object sender, EventArgs e)
            {
                if(System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
                {
                    string path = ApplicationDeployment.CurrentDeployment.DataDirectory; //Get installed path
                    AppDomain.CurrentDomain.SetData("DataDirectory", path);//set the DataDirectory 
                }
            }

Finally, based on my test, I can get the information from the mdf file after I publised it and installed it in another computer.

Jack J Jun
  • 5,633
  • 1
  • 9
  • 27
  • Hi, Thanks for the answer (specially including image). About `Form1_Load()` isn't it better if I put it in `Program.cs` file `static void Main()` function? because my app first opens login form and then form1 (PS: login form will be closed on successful login) that's why I said if i put it in `main()` function. What do you suggest? – mafortis Jul 26 '21 at 09:53
  • Oh and currently my DB file is not in any folder (screenshot) https://ibb.co/f2NMbKq would that be ok? or I must put it in folder? – mafortis Jul 26 '21 at 09:56
  • @mafortis, If you want to want to access the file in the app directly after published, you could try the code 'ApplicationDeployment.CurrentDeployment.DataDirectory;'. Also, I have changed my code in my answer. – Jack J Jun Jul 27 '21 at 01:45
  • I am using package installer (visual Studio extension) to create setup file. Should I also add db file manually in my setup files or it will be automatically included? – mafortis Jul 27 '21 at 05:11
  • @mafortis, based on my research, it is necessary for you to add the db file in your setup files manually. You could refer to the link [Include folder in setup project](https://stackoverflow.com/questions/1108840/include-folder-in-setup-project). – Jack J Jun Jul 27 '21 at 06:53
  • Hi, I've tried accepted answer in your link but I couldn't find any file system in view `View" > "File System` – mafortis Jul 27 '21 at 07:37
  • @mafortis, you can look at this picture [1]: https://i.stack.imgur.com/CxGmS.jpg to find add the folder . – Jack J Jun Jul 27 '21 at 08:05
  • So I just select my mdf file there? – mafortis Jul 27 '21 at 11:06
  • 1- Should I make any changes in my mdf file before putting it there? 2- what if later I update my database file, should copy it again or it will get updates automatically? – mafortis Jul 27 '21 at 11:08
  • No comment on my question? – mafortis Jul 28 '21 at 15:47
  • @mafortis, I think your problem may be solved in [here](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects&ssr=false#qna). You could ask a new question here. – Jack J Jun Jul 30 '21 at 01:39
0

In production mode |DataDirectory| refers to 'bin' directory, not 'app_data'. If you placed the .mdf file in the app_data directory, you can change it like this:

|DataDirectory|\SampleDatabase.mdf to |DataDirectory|\app_data\SampleDatabase.mdf

<add name="SampleDatabaseWalkthrough.Properties.Settings.SampleDatabaseConnectionString"
        connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\app_data\SampleDatabase.mdf;Integrated Security=True"
        providerName="System.Data.SqlClient" />

Update1:

I'm sending some code. I just want to give you an idea. You can change it for your situation.

private void Form1_Load(object sender, EventArgs e)
{
    if (!IsExist())
    {
        CreateDatabase();
        CreateTables();
    }
}

// Create the Database
private void CreateDatabase()
{
    string basePath = Environment.CurrentDirectory;
    string mdfFile = "TestDatabase.mdf";
    string ldfFile = "TestDatabase_Log.mdf";
    string mdfFullPath = System.IO.Path.Combine(basePath, "Data", mdfFile);
    string ldfFullPath = System.IO.Path.Combine(basePath, "Data", ldfFile);

    SqlConnection myConn = new SqlConnection("Server=.;Data Source=(LocalDB)\\MSSQLLocalDB;Integrated security=SSPI;database=master");
    string str = "CREATE DATABASE TestDatabase ON PRIMARY " +
            "(NAME = TestDatabase, " +
            $"FILENAME = '{mdfFullPath}', " +
            "SIZE = 2MB, MAXSIZE = 10MB, FILEGROWTH = 10%)" +
            "LOG ON (NAME = MyDatabase_Log, " +
            $"FILENAME = '{ldfFullPath}', " +
            "SIZE = 1MB, " +
            "MAXSIZE = 5MB, " +
            "FILEGROWTH = 10%)";


    SqlCommand myCommand = new SqlCommand(str, myConn);
    try
    {
        myConn.Open();
        myCommand.ExecuteNonQuery();
        MessageBox.Show("DataBase is Created Successfully", "MyProgram", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    catch (System.Exception ex)
    {
        MessageBox.Show(ex.ToString(), "MyProgram", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    finally
    {
        if (myConn.State == ConnectionState.Open)
        {
            myConn.Close();
        }
    }
}

// Create the tables and other stuff that you want
private void CreateTables()
{
    string conStr = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Data\TestDatabase.mdf;Integrated Security=True;Connect Timeout=30";

    SqlConnection myConn = new SqlConnection(conStr);
    string str = @"CREATE TABLE [dbo].[TestTable]
                    (
                        [Id] INT NOT NULL PRIMARY KEY, 
                        [Test] NVARCHAR(50) NULL
                    )";

    SqlCommand myCommand = new SqlCommand(str, myConn);
    try
    {
        myConn.Open();
        myCommand.ExecuteNonQuery();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString(), "MyProgram", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    finally
    {
        if (myConn.State == ConnectionState.Open)
        {
            myConn.Close();
        }
    }
}

// Check if there is the database
private bool IsExist()
{
    string basePath = Environment.CurrentDirectory;
    string mdfFile = "TestDatabase.mdf";
    string mdfFullPath = System.IO.Path.Combine(basePath, "Data", mdfFile);

    return System.IO.File.Exists(mdfFullPath);
}
Saeid Amini
  • 1,313
  • 5
  • 16
  • 26
  • Thanks for answer, and I have same question for you as I asked Jack, do I have to copy my mdf file to my installer? Should I make any changes in that mdf file before I copy it (if it's required to be copied)? TBH this is my first attempt and I'm absolute newbie so I need like step by step guidance to make it work (as I explained in my bounty description). Thank you – mafortis Jul 29 '21 at 11:50
  • It's no matter. You can copy it or make it at the first run if it's not exist. And you don't need to change anything. I think the problem is in the `path`, not in the file format or anything else. – Saeid Amini Jul 31 '21 at 09:55
  • Let say I don't copy my db file, can you guide me how to generate one at first run? Maybe that fixed my problem – mafortis Jul 31 '21 at 10:23
  • Are you using `Microsoft SQL Server Database file` data source? – Saeid Amini Jul 31 '21 at 11:18
  • I think so (I don't know the long name of it as you mentioned it) but the file it creates is `.mdf` format and it is offline (local). I am not using any online database for this. – mafortis Jul 31 '21 at 11:20
  • If you are using ORMs like Entity Framework, you can [configure it to make database if it not exist](https://stackoverflow.com/questions/42355481/auto-create-database-in-entity-framework-core). If not, you can create your database at the first run. Just look at this [helpful example](https://learn.microsoft.com/en-us/troubleshoot/dotnet/csharp/create-sql-server-database-programmatically)? – Saeid Amini Jul 31 '21 at 11:41