I'm using C# and I have a function for check this values. ( Name, Identity Number And School Number )
My records on text file.
If two or more same name and surname (different identity number and school number) in text file, I need to show all of them.
How Can I do it with loop ?
Note = identityBox is my TextBox name and identity number in there. This code just run for one record. This is identityFounder Code. Name and Surname founder Code is same with this. I will use next and previous buttons for see all records. Here is the C# Codes. Help me please. Thank you.
void identityFounder()
{
int inout = 0;
double identityNo = Convert.ToDouble(founderBox.Text);
String[] line = File.ReadAllLines("C:\\OgrenciBilgisi_v2.txt");
for (int i = 0; i < line.Length; i++)
{
if (line[i].Contains(identityNo.ToString()))
{
temp = i;
inout = 1;
break;
}
else
{
inout = 0;
continue;
}
}
if (inout == 1)
{
name.Text = line[temp - 3];
surname.Text = line[temp - 2];
address.Text = line[temp - 1];
identity.Text = line[temp];
school.Text = line[temp + 1];
number.Text = line[temp + 2];
faculty.Text = line[temp + 3];
deparrtment.Text = line[temp + 4];
class.Text = line[temp + 5];
}
else
{
MessageBox.Show("Record cannot found file.","Warning",MessageBoxButtons.OK
,MessageBoxIcon.Information);
}
}
First, a couple of quick asides:
inout should be a bool, not an int.
You can drop the else block; it isn't doing anything.
Now, more broadly, what you want to do is keep track of which names you've already seen as you parse the records. This is actually going to be faster and easier if you parse all of the identities at once. Since your lines are not structured except by order, the only way to do this is with a state machine.
I would just make a small console app that parses the text file, looking for duplicate names, and if it finds any then report the file name (or print the entire file to the screen or whatever; I'm not clear on what you mean by "show all of them"). Maybe something like:
struct Record
{
public string Name, Surname;
public int Identity, School;
}
class Program
{
static void Main(string[] args)
{
const string path = #"C:\OgrenciBilgisi_v2.txt";
var position = 0;
var record = new Record();
var records = new Dictionary<string, Record>(); // key is the concatenation of name and surname
using (var reader = new StreamReader(path))
{
var line = reader.ReadLine();
if (line == "---") // TODO use your record delimiter here
{
// start of new record. compare the existing one and commit it if all fields have been written to
if (position == 9)
{
// compare records
var key = record.Name + record.Surname;
if (records.ContainsKey(key))
{
// this is a duplicate student name. confirm that the id and school # are different
if (records[key].Identity == record.Identity &&
records[key].School == record.School)
{
// id and school are the same, so this is an entirely duplicate record
}
else
{
// id and school are different, but name and surname are the same
// TODO: show all records
return;
}
}
else
{
records.Add(key, record);
}
}
else
{
Console.Error.WriteLine("Not all fields in record. Malformed data.");
}
position = 0;
record = new Record();
}
else
{
switch (position)
{
case 0:
record.Name = line;
break;
case 1:
record.Surname = line;
break;
case 3:
int id;
if (int.TryParse(line, out id))
{
record.Identity = id;
} // else there's an error
break;
case 4:
int school;
if (int.TryParse(line, out school))
{
record.School = school;
} // else there's an error
break;
}
position++;
}
}
}
}
This assumes that your data is pretty well formatted; adding error checking is left as an exercise for the reader :)
Related
fileName = txtBxFileNamePath.Text;
if (File.Exists(fileName))
{
if (txtBxDate.Text != null && txtBxNumber.Text != null && txtBxUnit.Text != null && txtBxUnitPrice.Text != null && txtBxShipTo.Text != null
&& txtBxOrdered.Text != null && richTxBxDesc.Text != null)
{
try
{
int higherThanZero = Int32.Parse(txtBxNumber.Text);
if (higherThanZero > 0)
{
using (StreamReader reader = File.OpenText(fileName))
{
string[] lines = File.ReadAllLines(fileName);
for (int i = 0; i < lines.Length - 1; i++)
{
string firstNum = lines[i].Substring(0, 2);
if (firstNum == txtBxNumber.Text)
{
string record = "hello ";
lines[i].Replace(lines[i], record);
}
else
{
int orderNum = Int32.Parse(txtBxOrdered.Text);
int unitPriceNum = Int32.Parse(txtBxUnitPrice.Text);
double tax = .13;
int taxInt = (int)tax;
int amount = orderNum * unitPriceNum;
string amountStr = amount.ToString();
int amountTotal = amount * taxInt;
string amountTotalStr = amountTotal.ToString();
amountList.Add(amountStr);
amountTotalList.Add(amountTotalStr);
string record = amountTotalStr.PadRight(30) + amountStr.PadRight(30);
richTxtBxRecord.Text += record + "\n";
using (StreamWriter write = new StreamWriter(fileName, true))
{
write.WriteLine(record + "\n");
write.Close();
}
}
}
}
}
else
{
richTxtBxError.Text += "Textbox Number must contain a digit higher than 0 ";
}
}
catch
{
richTxtBxError.Text += "Please make sure number text box is a digit";
}
}
else
{
richTxtBxError.Text += "please make sure that no text boxes are empty";
}
}
else
{
richTxtBxError.Text += "Please select a file that already exists";
}
I am having an issue where once i get past the try-catch statement "please make sure number is a digit, no code executes. I am trying to obtain the first few characters in a text file and match it with the users input. If the input is the same as what is already inserted in the text file, i update the whole record. If there is no match (non existent number) i write in a brand new record.
I can't quite follow your logic, but I tried. You should be able to take this code and do what you want (whatever it is).
I started by declaring some class level variables.
private DateTime _dateValue;
private int _numberValue;
private decimal _unitPrice;
private int _numberOrdered;
Then, since you have so many preconditions and so many text boxes, I factored out the validation and setting of these variables. It makes the logic (whatever it supposed to be) much easier to follow:
private bool ValidateUserEntry()
{
bool isError = false;
if (!File.Exists(txtBxFileNamePath.Text))
{
AddError("File Name must exist");
isError = true;
}
if (txtBxDate.Text == string.Empty || !DateTime.TryParse(txtBxDate.Text, out var _dateValue))
{
AddError("The date must be a valid date");
isError = true;
}
if (txtBxNumber.Text == string.Empty || !int.TryParse(txtBxNumber.Text, out _numberValue) ||
_numberValue <= 0)
{
AddError("You must enter a number greater than 0 for [Number]");
isError = true;
}
if (txtBxUnitPrice.Text == string.Empty || !decimal.TryParse(txtBxUnitPrice.Text, out _unitPrice) ||
_unitPrice <= 0.0m)
{
AddError("The unit price must be a positive decimal number");
isError = true;
}
if (txtBxShipTo.Text == string.Empty)
{
AddError("A ship to address is required");
isError = true;
}
if (txtBxOrdered.Text == string.Empty || !int.TryParse(txtBxOrdered.Text, out _numberOrdered) ||
_numberOrdered <= 0)
{
AddError("The Number ordered must be a number greater than 0");
isError = true;
}
if (richTxBxDesc.Text == string.Empty)
{
AddError("A description is required");
isError = true;
}
return !isError;
}
I also added two utility functions for managing the error list:
private void ClearError()
{
richTxtBxError.Text = string.Empty;
}
private void AddError(string errorMessage)
{
richTxtBxError.Text += (errorMessage + Environment.NewLine);
richTxtBxError.SelectionStart = richTxtBxError.Text.Length;
richTxtBxError.SelectionLength = 0;
}
Now comes the real code. Near as I can tell, you want to scan a text file. If the number in the first few character positions matches a number in your input, then you change the line to some constant text. Otherwise, you want to do a calculation and put the results of the calculation on the line of text.
My input file looks like this:
1 First
2 Second
3 Third
12 Twelth
13 Thirteenth
34 Thirty-fourth
and the code that I run looks like what's below. The logic makes no sense, but it was what I could discern from your code. Instead of trying to do things on the fly to a file (which never really turns out well unless you are really careful), I gather the output into a List<string>. Once I have all the output, I put it in a text box control and overwrite the file.
ClearError();
//check pre-conditions
if (!ValidateUserEntry())
{
return;
}
string[] lines;
using (StreamReader reader = File.OpenText(txtBxFileNamePath.Text))
{
lines = File.ReadAllLines(txtBxFileNamePath.Text);
}
List<string> newLines = new List<string>();
for (var lineIndex = 0; lineIndex < lines.Length; ++lineIndex)
{
var line = lines[lineIndex];
if (line.Length > 2 && int.TryParse(line.Substring(0, 2), out var linePrefixNumber) &&
linePrefixNumber == _numberValue)
{
newLines.Add("Bingo, hit the right record");
}
else
{
decimal tax = .13m;
var amount = _numberOrdered * _unitPrice;
var amountTotal = amount * (1m + tax);
//amountList.Add(amount.TosString());
//amountTotalList.Add(amountTotal.ToString());
var newRecord = $"{amountTotal,30:C}{amount,30:C}";
newLines.Add(newRecord); //every record but one will be the same, but, such is life
}
}
//at this point, the newLines list has what I want
//put it in the text box
richTxtBxRecord.Text = string.Join(Environment.NewLine, newLines);
//and write it out
using (StreamWriter write = new StreamWriter(txtBxFileNamePath.Text, append:false))
{
write.Write(richTxtBxRecord.Text);
write.Flush();
}
With inputs that look like:
Number: 12
Number Ordered: 3
Unit Price: 1.23
The output (oddly enough - but it's what I could figure from your code) looks like:
$4.17 $3.69
$4.17 $3.69
$4.17 $3.69
Bingo, hit the right record
$4.17 $3.69
$4.17 $3.69
You can see that the input line that had the 12 at the start gets switched for bingo. The rest get the same information. I'm sure that's not what you want. But, with this code, you should be able to get something that you'd like.
Also note that I treat all the currency values as decimal (not int or double). For the life of me, I have no idea what you were trying to do with the taxInt variable (it will always be zero the way you have coded it). Instead, I did a rational tax calculation.
All of the code below the catch block is inside an else block, so I wouldn't expect it to execute. If you want something to execute after the catch, remove it from the else block.
Trying to complete a stock system in a console application and thus I am stuck on this part, to make sure that a user can't have a duplicate 8 digit long ID number, my issue is as follows.
Basically I am unsure why this code will not work, I'm probably missing a very obvious piece of code here, help would be appreciated, have tried changing values around already so have more than likely overlooked a value.
static int checkIDNumber(int ID)
{
// Check the number passed in & then loop through all the lines...
// If number is taken then output error, because id exists already
// Else allow the value to be used in the stock system.
int IDNumber = ID;
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
string lineValues;
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
Console.WriteLine("Id number is currently already taken.");
}
else
{
return IDNumber;
}
}
}
}
I pass in my value from this line in another procedure where it is defined in the local scope.
stockID = checkIDNumber(stockID);
Here is the full code:
class Program
{
static void Main(string[] args)
{
char menuOption = '0';
while (menuOption != '3')
{
DisplayMenuOption();
menuOption = GetMenuOption();
switch (menuOption)
{
case '1':
AddStock();
break;
case '2':
CheckStock();
break;
case '3':
Console.WriteLine("Goodbye");
break;
default:
Console.WriteLine("That is not a valid option");
break;
}
}
// Keep it all happy for a screenshot ;)
Console.ReadLine();
}
static void DisplayMenuOption()
{
Console.WriteLine("Do you wish to Add Stock(1) or Check Stock(2) or Exit(3)?");
}
static void DisplayStockOption()
{
Console.WriteLine("Do you want to search by ID(1) or by Name(2), Delete current stock(3) or Exit(4)?");
}
static char GetMenuOption()
{
char userChoice = '0';
userChoice = Convert.ToChar(Console.ReadLine());
return userChoice;
}
static void CheckStock()
{
char menuOption = 'a';
while (menuOption != '4')
{
DisplayStockOption();
menuOption = GetMenuOption();
switch (menuOption)
{
case '1':
SearchID();
break;
case '2':
SearchName();
break;
case '3':
RemoveStock();
break;
case '4':
Console.WriteLine("Goodbye");
break;
default:
Console.WriteLine("That is not a valid option");
break;
}
}
}
static void RemoveStock()
{
List<string> tempList = new List<string>();
string lineValues = "";
bool found = false;
int ID = 0;
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
Console.Write("Please enter the ID number to delete: ");
ID = Convert.ToInt32(Console.ReadLine());
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(ID.ToString()) == false)
{
tempList.Add(lineValues);
}
else
{
found = true;
}
}
}
if (found == true)
{
using (StreamWriter sw = new StreamWriter("Stockfile.txt", false))
{
for (int i=0; i < tempList.Count; i++)
{
sw.Write(tempList[i]);
sw.WriteLine();
}
}
}
}
static void SearchName()
{
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
string name;
Console.Write("Please enter the name: ");
name = Console.ReadLine();
while (sr.EndOfStream == false)
{
string lineValues = sr.ReadLine();
if (lineValues.Contains(name))
{
Console.WriteLine("{0}", lineValues);
}
else
{
Console.WriteLine("{0} does not exist in this stock system!",name); // Could try to match a similar string incase of spelling errors here, although after looking at it it may be a bit far for what is being required now, but in the real world application this would be a must else people would mistype words thus not having an exact match.
}
}
}
}
static void SearchID()
{
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
int IDNumber;
string lineValues;
Console.Write("Please enter the ID number: ");
IDNumber = Convert.ToInt32(Console.ReadLine());
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
Console.WriteLine("{0}", lineValues);
}
else
{
Console.WriteLine("{0} does not exist in this stock system!", IDNumber); // Could try to match a similar string incase of spelling errors here, although after looking at it it may be a bit far for what is being required now, but in the real world application this would be a must else people would mistype words thus not having an exact match.
}
}
}
}
static int checkIDNumber(int ID)
{
// Check the number passed in & then loop through all the lines...
// If number is taken then output error, becuase id exists already
// Else allow the value to be used in the stock system.
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
int IDNumber;
string lineValues;
Console.Write("Please enter the ID number: ");
IDNumber = Convert.ToInt32(Console.ReadLine());
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
Console.WriteLine("Id number is currently already taken.");
}
else
{
ID = IDNumber;
return ID;
}
}
}
}
static void AddStock(int IDNumber)
{
using (StreamWriter sw = new StreamWriter("Stockfile.txt", true))
{
int stockID = 0;
int stockQuantity = 0;
double stockPrice = 0.00;
string stockName = "";
string s = ""; // Being Lazy here, to convert to when needed.
while (stockID.ToString().Length != 8)
{
Console.Write("Please enter the stock ID number: ");
stockID = Convert.ToInt32(Console.ReadLine());
}
s = stockID.ToString();
sw.Write(s + "\t"); // Will only accept an 8 figure digit so is safe to have a single value here.
while (stockName.Length <= 2) // No fancy brands here......
{
Console.Write("Please enter the name of the stock: ");
stockName = Console.ReadLine();
}
s = stockName;
sw.Write(s + "\t");
while (stockQuantity < 1) // Running a small shop here...
{
Console.Write("Please enter the quanity of stock: ");
stockQuantity = Convert.ToInt32(Console.ReadLine());
}
s = stockQuantity.ToString();
sw.Write(s + "\t");
while (stockPrice < 0.01) // Running a very small shop....
{
Console.Write("Please enter the price of the stock: ");
stockPrice = Convert.ToDouble(Console.ReadLine());
}
s = stockPrice.ToString();
sw.Write(s + "\t");
sw.WriteLine(); // TO create the new line.....
}
}
}
}
The problem is that you're only returning a value from inside the else block.
Your method needs to return a value regardless of which path the program takes through your code. You can fix this in any number of ways, depending on your requirements. For instance, you can have a "catch-all" return value at the bottom of the method so that if it passes through all your tests (i.e. if blocks) and reaches the bottom, as long as that's a meaningful result, it will return the catch-all value.
Alternatively, you could just make sure you put a return statement inside each of the code paths. For that, you'd need to add a return in the if portion of your if block, but you'd likely also still need a return outside of your while loop since that may never execute.
Again, it all depends on your needs.
It's at least logically possible that the file contains nothing but the ID. For example, if I enter "10" as an ID and the file is:
10
10
10
10
...
It might be the case that you know that that'll never actually happen, but the compiler can't really prove that it won't. From the compiler's "perspective," there's not really a difference between "might happen" and "can't prove that it won't happen."
Also, your logic is wrong. If you know that the user requested a duplicate ID, you don't need to check the rest of the file - you already know it's a duplicate.
Right now, if the first line of the file isn't the ID they requested, it'll allow the user to take it. For example, if the user requested "9" as an ID and the file is as follows:
3 -- It only actually checks this line
5
9 -- Obviously the ID is already taken here but it'll never check this line
2
1
See my comments below:
// I'd suggest making this "bool" - they already know what the ID number is,
// so there's no point in returning it back to them
static int checkIDNumber(int ID)
{
// Check the number passed in & then loop through all the lines...
// If number is taken then output error, because id exists already
// Else allow the value to be used in the stock system.
int IDNumber = ID;
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
string lineValues;
// In general, you shouldn't explicitly compare to "true" or "false."
// Just write this as "!sr.EndOfStream"
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
// In this case, you don't have to bother checking the rest of the file
// since you already know that the ID is taken
Console.WriteLine("Id number is currently already taken.");
}
else
{
// You actually can't return that at this point - you need to check
// the *entire* file before you conclude that it's not a duplicate
return IDNumber;
}
}
}
}
I'm making a console application and I need to be able to write, search and delete entries from within text files, I can write files into a notepad file but that's basically it, this is what I have to read the file:
public static void SearchDetails()
{
Console.WriteLine("Enter ID Number");
string myfile = System.IO.File.ReadAllText(#"C:\\file.txt");
System.Console.WriteLine(myfile);
}
This brings up all the text in the file but I need to be able to search for a specific number within the file and then brings up the next three lines below it. How to I get it to read the input so that it matches with a number in the text file and then bring up the next 3 lines?
So you can do whatever you want with the results but something like this is what you want
// Read the file and display next three lines
System.IO.StreamReader file = new System.IO.StreamReader("c:\\file.txt");
string line;
int lineCnt = 3;
while((line = file.ReadLine()) != null)
{
if (line.Contains(myID) & !bGet)
{
bool bGet = true;
}
if (bGet && lineCnt > 0)
{
bool bGet = true;
Console.WriteLine (line);
lineCnt--;
}
if(lineCnt == 0) {break;}
}
file.Close();
// Suspend the screen.
Console.ReadLine();
Considering you question and comments to answer, the final answer would be:
public static void SearchDetails()
{
Console.WriteLine("Enter ID Number");
int Id = 0;
int.TryParse(Console.ReadLine(), out Id);
string[] lines = System.IO.File.ReadAllLines(#"C:\\file.txt");
List<string> IdLines = lines.Where((x, i) => i % 4 == 0).ToList();
int IdLine = IdLines.IndexOf(Id);
if (IdLine != -1)
{ //then result found
//Id is what user searched for or
// string Id = lines[IdLine*4];
//string[] results = lines.Where((x, i) => i > IdLine * 4 && i < IdLine * 4 + 4).ToArray();
for(int i=IdLine*4;i<IdLine*4+4;i++)
System.Console.WriteLine(lines[i]);
}
else
{
Console.WriteLine("no results!");
}
}
Pretend that I'm asking the user to input an album to list down.
I have this fine,
but for some reason I cant figure out a way for them to be able to then delete the input that they have made.
This is the method that I have used to store any album input that they have
static void InsertNewAlbum()
{
//Variable for user input
string albumInput
//Ask for the user for details
Console.WriteLine("Enter the Title of the album you would like to store");
albumInput = Console.ReadLine();
//Process the input of the user to make it easier to search later on
albumInput = albumInput.ToUpper();
albumInput = albumInput.Trim();
//Find an empty spot within list
int nextAvailableSpace = FindSlot("");
if (nextAvailableSpace != -1)
{
//Put customer information within an empty slot into the car park
albumNames[nextAvailableSpace] = albumInput;
}
else
{
//Inform that the usercannot park as the parking space is full
Console.WriteLine("Sorry, but there are no available spaces left to store your album.");
Console.ReadLine();
}
}
Here's the how the "FindSlot" method goes, for anyone that curious
static int FindSlot(string albumName)
//Finding an empty slot for the user to put their car in
{
int result = - 1;
for (int index = 0; index < albumNames.Length; index++)
{
if (albumNames[index] == albumNames)
{
result = index;
break;
}
else if (albumName == "" && albumNames[index] == null)
{
result = index;
break;
}
}
return result;
}
albumNames is the string that it puts in album the customer puts in and it's a static string.
So yeah, the user can freely put in 10 albums, but when it comes to deleting an album I get stuck.
The album is listen within a string array. I've tried various things within my knowledge but nothing seems to be working.
Thanks for anyone that can help, it is quite complicated.
You always send "" to FindSlot, as you should be sending the albumInput. If you need to know if the album is present, first control all the albumNames if your input is present, then look for a space. Like:
static int FindSlot(string albumName)
//Finding an empty slot for the user to put their car in
{
for (int index = 0; index < albumNames.Length; index++)
{
if (albumNames[index] == albumName)
{
return index;
}
}
for (int index = 0; index < albumNames.Length; index++)
{
if (albumNames[index] == "")
{
albumNames[index] = albumName;
return index;
}
}
return -1;
}
And call it like:
static void InsertNewAlbum()
{
//Variable for user input
string albumInput;
//Ask for the user for details
Console.WriteLine("Enter the Title of the album you would like to store");
albumInput = Console.ReadLine();
//Process the input of the user to make it easier to search later on
albumInput = albumInput.ToUpper();
albumInput = albumInput.Trim();
//Find an empty spot within list
int nextAvailableSpace = FindSlot(albumInput);
if (nextAvailableSpace != -1)
{
Console.WriteLine(albumInput + " is stored successfully at slot" + nexAvailableSpace + "");
}
else
{
//Inform that the usercannot park as the parking space is full
Console.WriteLine("Sorry, but there are no available spaces left to store your album.");
}
Console.ReadLine();
}
To delete; you can use a similar function:
static int DeleteAlbum(string albumName)
//Finding an empty slot for the user to put their car in
{
for (int index = 0; index < albumNames.Length; index++)
{
if (albumNames[index] == albumName)
{
albumNames[index] = "";
return index;
}
}
return -1;
}
As your FindSlot function, you can return an integer to confirm deletion was successful. Like:
static void DeleteAnAlbum()
{
//Variable for user input
string albumInput;
//Ask for the user for details
Console.WriteLine("Enter the Title of the album you would like to store");
albumInput = Console.ReadLine();
//Process the input of the user to make it easier to search later on
albumInput = albumInput.ToUpper();
albumInput = albumInput.Trim();
//Find and delete the album from the List
int deletedIndex = DeleteAlbum(albumInput);
if (deletedIndex != -1)
{
Console.WriteLine(albumInput + " is deleted successfully");
}
else
{
//Inform that the usercannot delete
Console.WriteLine("Sorry, but there are no albums with given name.");
}
Console.ReadLine();
}
This code is not good, but I tried to keep your style.
I'm playing around with SQlite and sql commands. I'm trying to make a quizz program and I have a loop, that reads the questions and answers from my database and adds them to a list. I also have a bool that defines if the answer picked from the database is right or wrong.
My problem is that all this works fine the first time my loop executes the code and adds the true and false to my array of bools, but the 2'nd time my loop executes it throws the exception: SPECIFIED CAST NOT VALID. The method that fails looks like this: I made a comment where the code fails:
public void GetQuestion(int categoryRef)
{
Console.Clear();
int arrayIndex = 0;
int qListIndex = 0;
int idListIndex = 0;
List<string> qList = new List<string>();
List<int> idList = new List<int>();
int ansNr = 1;
bool[] isTrue = new bool[3];
SQLiteDataReader sqReader;
SQLiteCommand sqCommand = new SQLiteCommand(sqConnection);
try
{
sqCommand.CommandText = "SELECT Question, ID FROM Questions WHERE CategoryRef=" + categoryRef.ToString();
sqCommand.Connection.Open();
sqReader = sqCommand.ExecuteReader();
foreach (var item in sqReader)
{
qList.Add(sqReader.GetString(0));
idList.Add(sqReader.GetInt32(1));
}
sqReader.Close();
}
finally
{
sqConnection.Close();
}
for (int i = 0; i < qList.Count; i++)
{
try
{
sqCommand.CommandText = "SELECT Answer FROM Answers WHERE QuestionRef=" + idList[idListIndex].ToString();
sqConnection.Open();
sqReader = sqCommand.ExecuteReader();
Console.WriteLine(qList[qListIndex]);
foreach (var answer in sqReader)
{
Console.WriteLine(ansNr + ":" + sqReader.GetString(0));
ansNr++;
}
sqReader.Close();
}
finally
{
sqConnection.Close();
}
try
{
//THIS CODE FAILS 2'nd TIME IT LOOPS THROUGH
sqCommand.CommandText = "SELECT IsTrue FROM Answers WHERE QuestionRef=" + idList[idListIndex].ToString();
sqConnection.Open();
sqReader = sqCommand.ExecuteReader();
foreach (var item in sqReader)
{
isTrue[arrayIndex] = sqReader.GetBoolean(0); //<-- Specified cast is not valid.
arrayIndex++;
}
sqReader.Close();
}
finally
{
sqConnection.Close();
}
string input = Console.ReadLine();
int number = Convert.ToInt32(input);
switch (number)
{
case 1:
if (isTrue[0] == true)
{
Console.WriteLine("Correct");
}
if (isTrue[0] == false)
{
Console.WriteLine("False");
}
break;
case 2:
if (isTrue[1] == true)
{
Console.WriteLine("Correct");
}
if (isTrue[1] == false)
{
Console.WriteLine("False");
}
break;
case 3:
if (isTrue[2] == true)
{
Console.WriteLine("Correct");
}
if (isTrue[2] == false)
{
Console.WriteLine("False");
}
break;
}
Console.ReadLine();
idListIndex++;
qListIndex++;
arrayIndex = 0;
ansNr = 1;
}
}
Mostly likely, that you read DbNull from database, which cannot be cast to bool.
SQLite does not guarantee that the contents of any column will match the cast.
The GetBoolean is failing. You have 3 choices.
Try Catch
Test for Null
Replace your select with a query guaranteed to return true/false
SQLite version 3.7.8 2011-09-19 14:49:19
sqlite> CREATE TABLE Q (A);
sqlite> INSERT INTO Q VALUES (0);
sqlite> INSERT INTO Q VALUES (1);
sqlite> INSERT INTO Q VALUES ('T');
sqlite> INSERT INTO Q VALUES ('F');
sqlite> INSERT INTO Q VALUES ('Y');
sqlite> INSERT INTO Q VALUES (NULL);
sqlite> SELECT not ifnull(A==0 OR A=='F' OR A=='N',1) FROM Q;
0
1
1
0
1
0
In my case, EF was throwing the same error ("Specified cast not valid") because it couldnt resolve "1234" that SQLite was throwing at it.
The solution was to change the type of Name field from STRING to TEXT.
I was getting the same error because SQLite was returning a NULL.
Check for null: if (!sqlite_datareader.IsDBNull(4))
{// then do what is required}