fetch details from csv file on basis of name search c# - c#

Step 1: I have created a C# application called : Student details
Step 2: Added four TextBoxes and named them as :
Image below to refer:
Studentname.Text
StudentSurname.Text
StudentCity.Text
StudentState.Text
DATA INSIDE CSV FILE
vikas,gadhi,mumbai,maharashtra
prem,yogi,kolkata,maha
roja,goal,orissa,oya
ram,kala,goa,barka
Issue is How do I fetch all the data(surname,city,state) of user prem into above textboxes studentsurname,studentcity,studentstate from csv file when I search the name in textbox 1 => studentname.Text as prem
Below is the Code where I am stuck at return null and code inside Load_Script_Click
void Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
}
}
return;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Connection_fetch_details cd = Connection_fetch_details(con_env);
textusername.Text = cd.username;
}
==============================================================
Class file name : Address.class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DDL_SCRIPT_GENERATOR
{
public class Connection_fetch_details
{
public string username { get; set; }
}
}

The main problem is that your method is void, which means it doesn't return any value. So even though you may be finding a match, and creating a Connection_fetch_details object, you aren't returning that result back to the calling method.
This will fix that problem:
Connection_fetch_details Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
return cd; //return the object containing the matched username
}
}
return null;
}
Now it will return a Connection_fetch_details object if there is a match, or null if there is no match.
Next, you asked about returning all the fields, not just one. For that you would need to
a) add more properties to your object
b) add more code to populate those properties from the CSV
c) add code to populate the textboxes with the results from the object.
I'm also going to rename "username" to something more relevant, since none of the field names you described in the question match that. I'm also going to rename your class to "Student", and rename your search method, for the same reason.
Here's an example:
Student searchStudent(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
var split = line.Split(',');
if (split[0].Equals(searchName))
{
Student s = new Student()
{
firstname = searchName,
surname = split[1],
city = split[2],
state = split[3]
};
return s; //return the object containing the matched name
}
}
return null;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Student st = searchStudent(con_env);
textsurname.Text = st.surname;
txtcity.Text = st.city;
txtstate.Text = st.state;
}
namespace DDL_SCRIPT_GENERATOR
{
public class Student
{
public string firstname { get; set; }
public string surname { get; set; }
public string city { get; set; }
public string state { get; set; }
}
}

To accomplish your goal you have to further separate your problem in more granular steps and also distinguish between what you show in your UI and what informations you hold in the background in which format.
Create a class with the desired properties
public class Student { public string Name { get; set; } ... }
Learn how to read a csv file into such an object by using an existing library like CsvHelper or CsvReader.
When you have something like List<Student> from this part. Learn how you can visualize such a thing by using some Binding (also depends on the visualization you use Winforms, WPF, etc.).
Depending on the visualization component it already supports filtering or you need to filter by yourself by using e.g. LINQ to get the matching elements students.Where(student => student.Name.StartsWith(search)).
So far a lot of smaller problems which is simply to much to answer in a single one. Please try to break down your problems into smaller ones and search for their solutions. If you get stuck, ask a new question. That's all I can do for you now.

Related

How can I take data out of a text file line by line, part by part?

So I've been hitting my head against the wall trying to fill this list box with ID numbers saved into a text file. It's simple enough to get the lines out of the file and put them into a list box like that, but that ID number is also shared with more information that I want to display in other text boxes.
Edit
So this is a comma delimited file and here is an example of a student's stored information:
1234561, Hubert, Huphrey, 123 Apple, Townsville, Some State, MM/DD/YYYY
To put it plainly, I have this text file that has multiple ID #'s, Names, and Addresses, but I just want to display the ID #'s so they can be clicked on from their list box so the rest of the information can be displayed on screen.
I have already taken in a lot of advice, but my thick head can't figure out a few key points. Let me start off by sharing the code I have so far:
EDIT I have updated the method to work with the new Student Class. But Now I need to figure out how to work with the collection to get the properties of the class.
List<Student> colStudents = new List<Student>();
public MainWindow()
{
InitializeComponent();
}
private void btnGetStudents_Click(object sender, RoutedEventArgs e)
{
try
{
//Define a Student object variable with the name StudentInfo
string strStudentList;
// Declare a StreamReader variable for Student Object
StreamReader srStudent = new StreamReader("StudentData.txt");
// intIndex is the index of the contact chosen
int intIndex = lstStudentsID.SelectedIndex;
//Clear list box to avoid having it fill up too much
lstStudentsID.Items.Clear();
// Read the disk file structure
while (srStudent.EndOfStream == false)
{
// Read disk file into a string variable using the ReadLine method.
strStudentList = srStudent.ReadLine();
// Tokenize the string read from Student object
string[] tokenize = strStudentList.Split(',');
// Create a student object instance from the Student class.
Student StudentInfo = new Student();
// Set properties of Student object to array element containing the student data
StudentInfo.StudentID = int.Parse(tokenize[0]);
StudentInfo.StudentFirstName = tokenize[1];
StudentInfo.StudentLastName = tokenize[2];
StudentInfo.StudentAddressCity = tokenize[3];
StudentInfo.StudnetBirthDate = tokenize[4];
// Add student object to collection
colStudents.Add(StudentInfo);
// Add ID's to the listbox
lstStudentsID.Items.Add(StudentInfo.StudentID);
}
//Close disk file after all records have been read in
srStudent.Close();
}
catch(Exception ex)
{
MessageBox.Show("Experiencing the following disk problems: " + Environment.NewLine + ex.Message, "Disk File", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
}
EDIT:
Now that I have the while loop working well enough, I need to either figure out how to utilize the collection or just find a way to use a second and third method to print out the selected student's full name and address
Here's my new class:
public class Student
{
// Properties
private double _ID; // Student's ID, double just in case int is too small
private string _StudentFirstName; // Student's Name
private string _StudentLastName;
private string _StudentAddressStreet;
private string _StudentAddressCity;
private string _StudentBirthDate;
// Constructor
public Student()
{
_ID = 0;
_StudentFirstName = "";
_StudentLastName = "";
_StudentAddressStreet = "";
_StudentAddressCity = "";
_StudentBirthDate = "";
}
// ID Property
public double StudentID
{
get { return _ID; }
set { _ID = value; }
}
// First Name Property
public string StudentFirstName
{
get { return _StudentFirstName; }
set { _StudentFirstName = value; }
}
// Last name Property
public string StudentLastName
{
get { return _StudentLastName; }
set { _StudentLastName = value; }
}
// Address Property
public string StudentAddressStreet
{
get { return _StudentAddressStreet; }
set { _StudentAddressStreet = value; }
}
// Address Property
public string StudentAddressCity
{
get { return _StudentAddressCity; }
set { _StudentAddressCity = value; }
}
// Address Property
public string StudnetBirthDate
{
get { return _StudentBirthDate; }
set { _StudentBirthDate = value; }
}
}
You create dictionary with Key as studentid and value as file line
then using dictionary you can populate the list box
when user select particular list item retrieve the data from dictionary do not perform IO operation.
Dictionary studentInfo = new Dictionary();
static void Main(string[] args)
{
StreamReader Student = new StreamReader("StudentData.txt");
// intIndex is the index of the contact chosen
intIndex = lstStudentsID.SelectedIndex;
// Add student to colStudents list
colStudents.Add(Student.ToString());
// Read the disk file structure
while (Student.EndOfStream == false)
{
// Read disk file into a string variable using the ReadLine method.
strStudentInfo = Student.ReadLine();
// Tokenize the string read from Student object
string[] tokenize = strStudentInfo.Split(',');
// Create a student object instance from the Student class.
string temp = tokenize[0];
studentInfo.Add("Key", strStudentInfo);
}
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class TestReadFile {
public static void main(String args[]) {
String fileName = "StudentData.txt";
//read file into stream, try-with-resources
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Object reference set to null C# application [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
I have a Code where i am getting data from csv file on name search
if i type name in textbox1 then deatails related to that person are displayed in the remaining textboxes like surname , city , state
error :error screenshot 1: https://i.stack.imgur.com/VdVEZ.png
Download link of my project :
Link 1: https://www.sendspace.com/file/76vdv5
Code i have written
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace studentdetails
{
public partial class Form1 : Form
{
String filePath = "C:\\Users\\vikas\\Desktop\\d.csv";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
String con_env = textName.Text.ToString();
UserDetails ud = SearchFor(con_env);
textSurname.Text = ud.surname;
textCity.Text = ud.city;
textState.Text = ud.state;
}
UserDetails SearchFor(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
var bits = line.Split(',');
if (bits[0].Equals(searchName))
{
return new UserDetails()
{
surname = bits[1],
city = bits[2],
state = bits[3],
};
}
}
return null;
}
}
}
Userdetails Clas
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace studentdetails
{
class UserDetails
{
public string firstname { get; set; }
public string surname { get; set; }
public string city { get; set; }
public string state { get; set; }
}
}
Can anyone figure out why this error occurring
Object reference not set to an instance of an object.
This error occurs when your object is not initialized. In your case this error occurred while initializing UserDetails ud.
If you debug, you will realize you are returning instance of UserDetails from SearchFor() function.
When bits[0].Equals(searchName) matches at that time it is returning instance of UserDetails, but when this condition failed for all records in foreach then it is returning null which is not acceptable.
To resolve this issue instead of returning null from SearchFor() function, pass instance of UserDetails with default parameters.
Something like,
UserDetails SearchFor(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
var bits = line.Split(',');
if (bits[0].Equals(searchName))
{
return new UserDetails()
{
surname = bits[1],
city = bits[2],
state = bits[3],
};
}
}
return new UserDetails()
{
surname = "Default text",
city = "Default text",
state = "Default text",
}; //Here you need to fix
}
If you do something like above solution, then for failed condition it will set values of Surname, City and state to Default text which is not correct. To avoid this situation, you can put null check before assigning values to text box
private void Form1_Load(object sender, EventArgs e)
{
String con_env = textName.Text.ToString();
UserDetails ud = SearchFor(con_env);
//if ud is null then do not set values to text box
if(ud != null)
{
textSurname.Text = ud.surname;
textCity.Text = ud.city;
textState.Text = ud.state;
}
else //else block to set default value
{
textSurname.Text = "Default value";
textCity.Text = "Default value";
textState.Text = "Default value";
}
}
UserDetails SearchFor(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
var bits = line.Split(',');
if (bits[0].Equals(searchName))
{
return new UserDetails()
{
surname = bits[1],
city = bits[2],
state = bits[3],
};
}
}
return null;
}
If you look at your code your returning null from the method call below
UserDetails ud = SearchFor(con_env);
You then try to access a field from that object which is null
textSurname.Text = ud.surname;
You need to return the UserDetails that you are reading from the file
I did mention in my previous answer (when I gave this code) that the SearchFor method returns a null if the user is not found - when you do your search, and before you try to use the result, you should check if the return value is null. Something like:
UserDetails ud = SearchFor(con_env);
if(ud != null){
surnameTextbox.Text = ud.Surname;
...
} else {
MessageBox.Show("user not found");
}
Also note that you seem to have forgotten to set the name property of the userdetails object. Check the code i gave in the last answer. Also you should make the properties of the UserDetails class have Names Like This: Surname, City.. "public properties have names starting with a capital letter" is the rule in c# and if you're learning you should get used to doing it now

c# how to decide whether to add to sub-list or start new one

I have an sql query that provides me my data where I sometimes have lines that should be clustered (the data is aligned with an order by). The data is grouped by the field CAPName. Going through those rows line by line, I need to decide whether a new list should be initiated (content of CAPName differs to previous itteration), or whether the (already) initated list (from the previous iteration) should be added, too.
My pain lays with the location of the declaration of the relatedCapabilitySystem list.
I wanted to declare it within the if statement (Because, as I stated I need to decide whether the list from the previous iteration should be added too, or whether it should start a new list), but I can't as the compiler throws an exception, as the RLCapSys.Add(rCs); is non-existing in this content (which is only theoretically true). I understand why the compiler throws this exception. But if I declare the list on a "higher" level, than I always have a new list, which I don't want in the case that the item should be added to the list defined in the iteration(s) (1 or more) before
So what I want to achieve is, generate the list RLCapSys and add to it, in case the previous iteration contains the same CAPName (for clustering), otherwise create a new list.
SqlCommand cmdDetail = new SqlCommand(SQL_SubSytemsToCapability, DBConDetail);
SqlDataReader rdrDetail = cmdDetail.ExecuteReader();
List<relatedCapility> RLCaps = new List<relatedCapility>();
string lastCapShown = null;
while (rdrDetail.Read())
{
List<relatedCapabilitySystem> RLCapSys = new List<relatedCapabilitySystem>();
if (lastCapShown != rdrDetail["CAPName"].ToString())
{
//List<relatedCapabilitySystem> RLCapSys2 = new List<relatedCapabilitySystem>();
relatedCapility rC = new relatedCapility
{
Capability = rdrDetail["CAPName"].ToString(),
systemsRelated = RLCapSys,
};
RLCaps.Add(rC);
}
relatedCapabilitySystem rCs = new relatedCapabilitySystem
{
system = rdrDetail["name"].ToString(),
start = rdrDetail["SysStart"].ToString(),
end = rdrDetail["SysEnd"].ToString(),
};
RLCapSys.Add(rCs);
// method to compare the last related Capability shown create a new related Capabilty entry or add to the existing releated Capabilty related system list
lastCapShown = rdrDetail["CAPName"].ToString();
}
DBConDetail.Close();
and for reason of completness (but I think it is not needed here):
internal class CapabilitiesC
{
public List<Capability>Capabilities{ get;set;}
}
public class Capability
{
public string name { get; internal set; }
public string tower { get; internal set; }
public string color { get; internal set; }
public List<relatedCapility> related { get; set; }
}
public class relatedCapility
{
public string Capability { get; set; }
public List<relatedCapabilitySystem> systemsRelated { get; set; }
}
public class relatedCapabilitySystem
{
public string system { get; set; }
public string start { get; set; }
public string end { get; set; }
}
The purpose of your code is to take the input data and group it by capability. However, that is not immediately obvious. You can change your code to use LINQ so it becomes easier to understand and in the process solving your problem.
First you need a type to represent a record in your database. For lack of better name I will use Record:
class Record
{
public string System { get; set; }
public string Start { get; set; }
public string End { get; set; }
public string Capabilty { get; set; }
}
You can then create an iterator block to return all the records from the database (using an OR mapper like Entity Framework avoids most of this code and you can even shift some of the work from your computer to the database server):
IEnumerable<Record> GetRecords()
{
// Code to create connection and command (preferably in a using statement)
SqlDataReader rdrDetail = cmdDetail.ExecuteReader();
while (rdrDetail.Read())
{
yield return new Record {
System = rdrDetail["name"].ToString(),
Start = rdrDetail["SysStart"].ToString(),
End = rdrDetail["SysEnd"].ToString(),
Capability = rdrDetail["CAPName"].ToString()
};
}
// Close connection (proper using statement will do this)
}
Finally, you can use LINQ to perform the grouping:
var RLCaps = GetRecords()
.GroupBy(
record => record.Capability,
(capability, records) => new relatedCapility
{
Capability = capability ,
systemsRelated = records
.Select(record => new relatedCapabilitySystem
{
system = record.System,
start = record.Start,
end = record.End
})
.ToList()
})
.ToList();
Why not just assign it as NULL. The pattern would be
List<> myList = null;
if(condition)
{
myList = new List<>();
}
else
{
myList = previousList;
}
myList.Add();
previousList = myList;
I've got it working now. Thx everyone for your help. #martin, thx for your solution, you have put quite some effort into this, but that would have required for me to completely re-write my code. I am sure your approach would work and will be my next approach should I have a similar problem again.
It was a combination of the other answers that helped me figure it out. Let me show you what I ended up with:
SqlCommand cmdDetail = new SqlCommand(SQL_SubSytemsToCapability, DBConDetail);
SqlDataReader rdrDetail = cmdDetail.ExecuteReader();
List<relatedCapility> RLCaps = new List<relatedCapility>();
List<relatedCapabilitySystem> RLCapSys = new List<relatedCapabilitySystem>();
string lastCapShown = null;
while (rdrDetail.Read())
{
if (lastCapShown != rdrDetail["CAPName"].ToString())
{
RLCapSys = relatedCapabilitySystemList();
relatedCapility rC = new relatedCapility
{
Capability = rdrDetail["CAPName"].ToString(),
systemsRelated = RLCapSys,
};
RLCaps.Add(rC);
}
relatedCapabilitySystem rCs = new relatedCapabilitySystem
{
system = rdrDetail["name"].ToString(),
start = rdrDetail["SysStart"].ToString(),
end = rdrDetail["SysEnd"].ToString(),
};
RLCapSys.Add(rCs);
// method to compare the last related Capability shown create a new related Capabilty entry or add to the existing releated Capabilty related system list
lastCapShown = rdrDetail["CAPName"].ToString();
}
DBConDetail.Close();
So that's the section already shown bevor including my changes. Plus I added this:
private List<relatedCapabilitySystem> relatedCapabilitySystemList()
{
List<relatedCapabilitySystem> RLCapSys = new List<relatedCapabilitySystem>();
return RLCapSys;
}
Now I have new list reference everytime the CapName changes that is then added to the "higher" list. Before I had the issue of the very same list repeatedly assigned rather than a fresh one started. So thx again for your effort.

Reading file during LINQ query

I have a simple class, and I want to have the results from:
(which are correct so far)
Console.WriteLine(f.temp1);
Console.WriteLine(f.temp2);
in my Class Definitions temp1=Name; temp2=id
public class Definitions
{
public string Name { get; set; }
public string Id { get; set; }
}
class Program
{
static void Main()
{
ReadDefinitions();
}
public static void ReadDefinitions()
{
var files = from name in Directory.EnumerateFiles(Settings.Folder)
from id in File.ReadLines(name).Skip(2).Take(1)
select new
{
temp1= Path.GetFileNameWithoutExtension(name),
temp2= id
};
foreach (var f in files)
{
Console.WriteLine(f.temp1);
Console.WriteLine(f.temp2);
}
foreach (var f in files)
{
Console.WriteLine(f.temp1);
Console.WriteLine(f.temp2);
}
}
}
I know this is stupid with this temp stuff, but I could not manage to do it directly. :(
The goal is to:
Read the directory with many thousand files...
Put the name into Definitions.Name
Put line 3 of every file into Definitions.Id
So that I can access them anytime in my Program.
(I still need to trim the 3 left characters of line AND the 4 right characters of it,..but I'll probably manage that myself)
If understand correctly you just need to do this
var files = from name in Directory.EnumerateFiles(Settings.Folder)
select new
{
temp1= Path.GetFileNameWithoutExtension(name),
temp2= File.ReadLines(name).Skip(2).First()
};
If you want to skip the temp stuff then you can:
var files = from name in Directory.EnumerateFiles(Settings.Folder)
select new Definitions
{
Name = Path.GetFileNameWithoutExtension(name),
Id = File.ReadLines(name).Skip(2).First()
};

Adding list to list and reading from it?

I have a problem where I need to store a List in another Class/List.
I have this class:
public class InformationMyTravels
{
public string MyTravelsDate { get; set; }
public string MyTravelsFromLocation { get; set; }
public string MyTravelsToLocation { get; set; }
}
And I can populate a List and then save it to my isolated storage (AppSettings).
The problem is that when I have more than one "Overview" below, then the following code will just append the travel history.
What I need is a separation of "Overview", so that the List I populate for each Overview is saved in another Class/List, which can contain the x-number of "Overview" lists I fetch.
private async Task Fetch()
{
AppSettings localStorage = new AppSettings();
List<InformationMyTravels> mytravelsreturned = new List<InformationMyTravels>();
// I need to separate the returned data per Overview
foreach (Overview loaded in localStorage.OverviewSetting)
{
string mytravelsHtml = await WebRequests.LoadPageAsyncSpecificRKMyTravels(loaded.CardOverviewID);
HtmlDocument htmlDocumentmytravels = new HtmlDocument();
htmlDocumentmytravels.LoadHtml(mytravelsHtml);
foreach (HtmlNode table in htmlDocumentmytravels.DocumentNode.SelectNodes("//table[#class='table']"))
{
foreach (HtmlNode row in table.SelectNodes("tr"))
{
InformationMyTravels newTravel = new InformationMyTravels();
newTravel.MyTravelsDate = row.SelectSingleNode("td[1]").InnerText.Trim();
newTravel.MyTravelsFromLocation = row.SelectSingleNode("td[3]").InnerText.Trim();
newTravel.MyTravelsToLocation = row.SelectSingleNode("td[5]").InnerText.Trim();
// Here it just appends with newTravel's
mytravelsreturned.Add(newTravel);
}
}
mytravelsreturned.Reverse();
}
localStorage.MyTravelsSetting = mytravelsreturned;
}
So how do I take "mytravelsreturned" and add this to another Class/List?
And afterwards I need to select the specific listindex from the new class and load the travels into a listbox.ItemsSource
Wanted hierarchy:
Class/List
InformationMyTravels (0)
MyTravelsDate(0)
MyTravelsFromLocation (0)
MyTravelsToLocation(0)
MyTravelsDate(1)
MyTravelsFromLocation (1)
MyTravelsToLocation(1)
etc.
InformationMyTravels (1)
MyTravelsDate(0)
MyTravelsFromLocation (0)
MyTravelsToLocation(0)
MyTravelsDate(1)
MyTravelsFromLocation (1)
MyTravelsToLocation(1)
etc.
I then need to load e.g InformationMyTravels (1) into a listbox.ItemsSource
I hope it makes sense.
Below is the untested code(I am not on Windows currently). It should give you the Idea.
Class InformationMyTravelsList<T> : List<T>
{
public int id{get; private set;}
public void AddInfo(int ID, InformationMyTravels info)
{
this.id = ID;
this.Add(info);
}
}
Class Main
{
void myLogic()
{
InformationMyTravels info = new InformationMyTravels();
InformationMyTravelsList<InformationMyTravels> infoList = new InformationMyTravelsList<InformationMyTravels>();
infoList.AddInfo(info); //add as many you want
List<InformationMyTravelsList<InformationMyTravels>> myList = new InformationMyTravelsList<InformationMyTravels>>();
myList.Add(infoList);
myListBox.DataSource = myList;
}
}

Categories

Resources