The code you wrote isn't going to work correctly. The command is executed as soon as you call ExecuteReader
. At that point you haven't added the @imgname
parameter the command and hence the error. But even if you add the parameter before the command it still isn't going to work correctly. A reader just reads the results of a single command until there are no more results. If you want to run the command again (with a new value for a parameter) you have to execute the command again. Each reader is tied to one and only one execution of a command.
Looking at what you want to do you can execute the command once and pass it the list of all the filenames you want to exclude. Then you can use the reader to read the results so the structure of your code will work but you have to adjust the SQL query itself.
using (var conn = new SqlConnection(connString))
{
//Query for all images that don't match a file in the file system
var query = "SELECT ImageFileName FROM ImageDetails WHERE ImageFileName NOT IN (@existingImages)";
var cmd = new SqlCommand(query, conn);
//Build the list of filenames we don't care about
var existingParameterList = new List<string>();
var index = 0;
foreach (var existingFile in existingFiles)
{
var paramName = $"@existing{index++}";
cmd.Parameters.AddWithValue(paramName, existingFile);
existingParameterList.Add(paramName);
};
cmd.CommandText = cmd.CommandText.Replace("@existingImages", String.Join(",", existingParameterList));
//Execute the query
conn.Open();
using (var reader = cmd.ExecuteReader())
{
//Enumerate the results
while (reader.Read())
{
//Columns are zero based
var filename = reader.GetString(0);
Console.WriteLine(filename);
};
};
};
This code is replacing your existing code. But reading your last line it says you want to find the files in the filesystem that don't exist in the DB but your query isn't actually going to do that. It's going to return the filenames from the DB that aren't in the file system. If you want to go the other way then you'll need to get all the file names from the file system and then remove any that are in the database (so you'll need all the filenames in the DB).
var imagesInDB = new List<string>();
using (var conn = new SqlConnection(connString))
{
//Get all the image filenames
var query = "SELECT ImageFileName FROM ImageDetails";
var cmd = new SqlCommand(query, conn);
//Execute the query
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
imagesInDB.Add(reader.GetString(0));
};
};
};
//Now get all the files in the filesystem
//NOTE: This call returns the full path information but we assume the DB is only storing the filename
//so we will strip out the paths
var existingFiles = Directory.GetFiles(rootPath).Select(x => Path.GetFileName(x));
//Get all the files in the file system that aren't also in the DB
var missingFiles = existingFiles.Except(imagesInDB, StringComparer.OrdinalIgnoreCase);
//Remove the files from the filesystem
foreach (var file in missingFiles)
File.Delete(file);