问题
I've got this code in my Winforms app to create a table in an existing database, (which I created by following what is written here):
private void CreateTables()
{
string connStr = @"Data Source=
(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|
\AYttFM.mdf;Integrated Security=True";
using (var connection = new
System.Data.SqlClient.SqlConnection(connStr))
{
try
{
connection.Open();
using (var command = connection.CreateCommand())
{
StringBuilder sb = new StringBuilder();
sb.Append("CREATE TABLE [dbo].[AssignmentHistory] ");
sb.Append("(");
sb.Append("[Id] INT NOT NULL PRIMARY KEY, ");
sb.Append("[WeekOfAssignment] DATE NOT NULL,");
sb.Append("[TalkType] INT NOT NULL,");
sb.Append("[StudentID_FK] INT NOT NULL, ");
sb.Append("[AssistantID_FK] INT NOT NULL, ");
sb.Append("[CounselPoint] INT NOT NULL");
sb.Append(")");
command.CommandText = sb.ToString();
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
It runs without complaint, but no table is created. Refreshing both the Data Connection and its Tables folder in Server Explorer in Visual Studio Community 2015 show no tables.
Am I missing something in the code above?
Note: I broke the connStr over several lines above for formatting purposes; in the actual code, connStr is all on one line.
I'm also not able to connect to the .mdf file via LINQPad, using the "Default LINQ to SQL" and SQL Server Provider and navigating to the .mdf file in my project (C:\AYttFMApp\AYttFMScheduler\AYttFMScheduler\AYttFM.mdf). It tells me there is a network error:
I get that whether I use the default Server ".\SQLEXPRESS" or whether I set it to my machine name (which is the only entry beneath "Servers" in Visual Studio's Server Explorer).
UPDATE
I rebooted my laptop, but it didn't help. Server Explorer's Data Connections show nothing, even after I refresh, and trying to add one, with my machine name as the Server Name (after all, that is what it says the Server is there in Server Explorer) and selecting the .mdf file gives me the same error when testing the connection as LINQPad does.
UPDATE 2
Curiouser and curiouser: Now when I run my app, when it gets to the Create Table code, I get an exception msg that says the AssignmentHistory table has already been created. Yet if I look at Server Explorer, although the database itself is back again, its Tables folder is still empty. How can the table both be there and not be there?
I'm still wondering if the properties set on the .mdf file are wrong; as I wrote in a comment below, the properties are all the defaults: "Copy to Output Directory" is set to "Copy Always" and "Build Action" is set to "Content" Should either of these be changed?
回答1:
If the code does not throw any exceptions on line command.ExecuteNonQuery()
then the query did finish and the table should be there. It could be that you are just looking at the wrong database as you are using the LocalDb
. If the project has included the .MDF as a file and it is marked to always be copied to the destination directory then what is happening is that VS is always looking at the unaltered copy and the Execute statement always completes during debugging because the unaltered copy is always replacing the copy that is used at run time.
The DataDirectory
specifies a placeholder for a location that is usually assigned in the application startup. You can get the full path to the actual .mdf
file being used like so:
var fullFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.GetData("DataDirectory").ToString(), "AYttFM.mdf");
I have appended the name of your .mdf
LocalDb to the end of the path.
You can add this line of code and get the path of the file and then open this instance up with the Visual Studio table designer.
Alternatively you can change the connection string and hard code it to a specific instance of your .mdf file that is guaranteed not to change when you do a build on the project.
Edit based on your latest edits
"Object reference not set to an instance of an object" is what I get after running the line you provided.
I made the assumption you were setting the DataDirectory
location manually, my apologies. If you do not set the variable manually then for a windows application the default location is the .exe path. So the code should be updated to the following:
var fullFilePath = System.IO.Path.Combine(System.Reflection.Assembly.GetExecutingAssembly().Location.ToString(), "AYttFM.mdf");
This will probably resolve to something like .\yourProjectFolder\debug\bin\AYttFM.mdf
.
The properties are all the defaults: "Copy to Output Directory" is set to "Copy Always" and "Build Action" is set to "Content"
So that affirms what I wrote earlier. Every time you do a build it will copy the .mdf to your executable directory and basically refreshes the database to its original state. Note that you can do multiple runs from visual studio which means that if everything has already been compiled and nothing has changed a new .exe and content will not be re-copied over the existing one. This is why you are sometimes seeing an exception and other times you are not, it just depends on if the .mdf was overwritten or not.
Should either of these be changed?
This should be OK but it depends on if it's ok to start with a clean slate every time. That is really up to you, here are the available options you have:
From MSDN - File Properties
Copy to Output Directory Property
This property specifies the conditions under which the selected source file will be copied to the output directory. Select Do not copy if the file is never to be copied to the output directory. Select Copy always if the file is always to be copied to the output directory. Select Copy if newer if the file is to be copied only when it is newer than an existing file of the same name in the output directory.
If you want to open the .mdf file all you have to do is double click on it in the VS project, it should open up in Server Explorer
-> Data Connections
. There is no reason to open the output file (the copy of the .mdf) in your designer, I would only edit the file in your project as with your current setup this is the master file that will overwrite the output file every time.
I have no experience with LINQPad so I can't say if this application can attach to a LocalDb instance or not. Here is a post about how to possibly do this from a previous SO question.
回答2:
Open SQL Server configuration manager and check if your server is running. If it's not - then run it:
来源:https://stackoverflow.com/questions/35282380/why-is-my-table-not-being-created