Setting variable types from CSV - c#

var csv =
from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = customerRecord[1],
project = customerRecord[2],
projectCode = customerRecord[3]
};
public class Customer
{
public string contactID { get; set; }
public string surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
}
I'd like to be able to read the surveyDate as a DateTime in order to compare it with other DateTime fields I'm joining to the csv file.
I've tried just setting surveyDate as Date.Time in the class, and I've tried converting it in the select statement, but both fail with the following error:
FormatException: The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.
I do have to work with the csv file, so I can't add the data to sql server.
contactID,responseDate,project,projectID
1,6/4/2009,0-3 months,1
2,6/11/2009,0-3 months,1

You need to parse it when reading as well as changing the type. I'm not sure how you tried it in the first place. Also, use DateTime.ParseExact if you know the format.
var csv =
from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
public class Customer
{
public string contactID { get; set; }
public DateTime surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
}
Judging by the error you just posted, I think it's probably double-quoted. Try trimming the quotes:
DateTime.Parse(customerRecord[1].Trim('"'))

Right... Because you can never know what the input will be from the CSV you can't always try and implicitly convert the string to a DateTime and because you want to do the convert of a string within the select a way to do this is an extension method.
public static class StringExtensions
{
public static DateTime TryParseDate(this string strToParse)
{
DateTime dt = new DateTime();
DateTime.TryParse(strToParse, out dt);
return dt;
}
}
Then when you want to convert in the select do it like this:
var csv = from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = customerRecord[1].TryParseDate(),
project = customerRecord[2],
projectCode = customerRecord[3]
};
You have your own method. Hope this helps and works for you.
The string you want to parse will be passed to the method and then you can handle it and return a valid date time, handling incorrect inputs.
http://msdn.microsoft.com/en-us/library/bb383977.aspx
See this link for an explanation

After changing Customer so that SurveyDate is a DateTime then:
select new Customer()
{
contactID = customerRecord[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
You may need to use forms of Parse or ParseExact that take a format string, to be sure of the correct result. That format string depends on the format used in the file.
Alternatively, you could create a Parse static method on Customer:
public class Customer
{
public string contactID { get; set; }
public DateTime surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
public static Customer Parse(string line)
{
var parts = line.Split(',');
return new Customer{
contactID = parts[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
};
Then:
var csv =
from line in File.ReadLines("C:/file.csv")
select Customer.Parse(line);
This has an advantage if obtaining a Customer from such a formatted string happens more than once in your code. It needlessly fills Customer with cruft if this is the only place you do it. Note I favour ReadLines over ReadAllLines to get a line at a time rather than read the whole thing before starting do produce customers.
Incidentally, .NET conventions favour capitals on property names. SurveyDate rather than surveyDate etc.

I've tried just setting surveyDate as Date.Time in the class, and I've tried converting it in the select statement, but both fail.
Well you need to do both. You need to change the property type (ideally fixing the naming at the same time to follow conventions) and change where you're setting it, probably using DateTime.ParseExact, specifying the format and probably the invariant culture.
(I'm assuming you know the format of the date in the file - I would strongly advise you to use DateTime.ParseExact rather than just letting the framework try various formats until it finds one which works.)
EDIT: Now that we've seen the file, it looks like you'd want either
DateTime.ParseExact(text, "d/M/yyyy", CultureInfo.InvariantCulture)
or:
DateTime.ParseExact(text, "M/d/yyyy", CultureInfo.InvariantCulture)
... but we can't tell which, as we don't know whether "6/4/2009" means April 6th or June 4th.

You should convert your customerRecord[1] string to a DateTime.
var csv =
from line in File.ReadAllLines("C:/file.csv")
let customerRecord = line.Split(',')
select new Customer()
{
contactID = customerRecord[0],
surveyDate = DateTime.Parse(customerRecord[1]),
project = customerRecord[2],
projectCode = customerRecord[3]
};
public class Customer
{
public string contactID { get; set; }
public DateTime surveyDate { get; set; }
public string project { get; set; }
public string projectCode { get; set; }
}

Related

Comma separated Names with multiple columns as group by using C#

I have a list which has following result set .
public class PrExport
{
public string pId { get; set; }
public string prName { get; set; }
public string hId { get; set; }
public string hName { get; set; }
public string np { get; set; }
public string ftId { get; set; }
public string paName { get; set; }
}
List<PrExport> prTable = new List<PrExport>();
prTable =some 3rdparty service returns the result set as below;
I want the result set set as below
This is the code I have used.
var res = from c in prTable
group c by new { c.pId, c.prName, c.hId, c.hName, c.np, c.ftId } into gr
select new PrExport()
{
pId = gr.Key?.pId,
prName = gr.Key?.prName,
hId = gr.Key?.hId,
hName = gr.Key?.hName,
np = gr.Key?.np,
ftId = gr.Key?.ftId,
paName = string.Join(",", gr.Select(c => c?.paName))
};
return prTable = res.ToList();
I'm getting the result set as below .Here I'm not getting comma seperated paName which I wanted.What am I missing here?
As others have pointed out your code seems to be fine.
I don’t know how you produced the pictures of the tables but if that is a CSV file opened in e.g. Excel, it will not allow a comma , inside one of the values unless you use semi colon ; as delimiter in your CSV file.
check this out it may help you.
https://stackoverflow.com/questions/48723477/linq-one-to-many-relations-as-comma-separated-values

String '22-05-1998' was not recognized as a valid DateTime

I am using CsvHelper library to read the data from a CSV file looks like
this
My code:
public class CsvTransaction
{
[Name("Account")]
public string Account { get; set; }
[Name("Amount")]
public int Amount { get; set; }
[Name("Date")]
public DateTime Date { get; set; }
[Name("Note")]
public string Note { get; set; }
}
public void call()
{
using (var StreamReader = new StreamReader(#"C:\Users\santo\Downloads\industry.csv"))
{
using (var csvReader = new CsvReader(StreamReader, CultureInfo.InvariantCulture))
{
var records = csvReader.GetRecords<CsvTransaction>().ToList();
Console.WriteLine(records.Count);
foreach(var item in records)
{
Console.WriteLine(item.Amount.GetType());
Console.WriteLine(item.Note.GetType());
CsvAddTransaction(item.Account, item.Amount, item.Date, item.Note);
}
}
}
}
when I call this call(), it is saying String '22-05-1998' was not recognized as a valid DateTime. all the other are giving exact datatypes I needed, but there is a problem with item.Date
Can anyone help me with this?
You have to define DateTime format, you are getting this error because parsing mechanism might be expecting something like "MM-dd-yyyy" and instead of that, it receives "dd-MM-yyyy".
Here's documentation which describes DateTime formatting in detail.
And here is url to potential solution to your problem.

Sorting a ListBox in c# with multiple fields

Is there a way to sort a list box on one field then another?
(I saw the other posts but I think this is a bit more involved). I could do this the long way but thought there was a faster shorthand version I just wasn't aware of.
Basically this reads a directory for all the folders in it with the format of:
DATENAME
I parse out the name from the date. I need to organize these by name THEN by date (the second filter is what is tripping me up).
So a folder of:
12012016TULLY
1202019LAVA
2202018LAVA
5162019CLOUD
5202020LAVA
would look like
5162019CLOUD
2202018LAVA
1202019LAVA
5202020LAVA
12012016TULLY
So this is what I have:
class MyListBoxItem
{
public string StudyBaseFolder { get; set; }
public string StudyName { get; set; }
public string UserLastName { get; set; }
public string StudyDate { get; set; }
}
List<MyListBoxItem> studiesAndFolders = new List<MyListBoxItem>();
//later int he code i build a list of studyNames (which is a path and I pasre the path here too)
foreach (string sn in studyName)
{
//get user name
String lastName = getLastName(sn);
String theDate = getDate(sn);
//can I organize this based on the LAST NAME THEN THE DATE
studiesAndFolders.Add(new MyListBoxItem { StudyBaseFolder = path, StudyName = sn, UserLastName = lastName, StudyDate = theDate });
}
Then I finally add this to the listbox.
listDirectories.Items.Clear();
//I do it this way so a double click on an item gets the object back and I can do things with it.
foreach(MyListBoxItem direc in studiesAndFolders)
{
listDirectories.Items.Add(direc);
}
listbox.sorted=true didn't help, and I am sure there might be an expression (LINQ to the rescue?). I was just going to do it the long way with a ton of cases when I take the studiesAndFolders and put it to the list.
This code sorts by name, then by date. And should be easy to read.
foreach(MyListBoxItem direc in studiesAndFolders.OrderBy(x => x.StudyName).ThenBy(x => x.StudyDate))
{
listDirectories.Items.Add(direc);
}
As others have noted, you should be storing the StudyDate as a DateTime unless you want it sorted alphabetically.
Firstly, change type of StudyDate to DateTime
class MyListBoxItem
{
...
public DateTime StudyDate { get; set; }
}
After, create new comparer
public class MyListBoxItemComparer : IComparer<MyListBoxItem>
{
public int Compare(MyListBoxItem x, MyListBoxItem y)
{
if (x.StudyName == y.StudyName)
{
return x.StudyDate.CompareTo(y.StudyDate);
}
return String.Compare(x.StudyName, y.StudyName, StringComparison.Ordinal);
}
}
Finally, use SortedSet instead of List
SortedSet<MyListBoxItem> studiesAndFolders = new SortedSet<MyListBoxItem>(new MyListBoxItemComparer());
For ordering based on the date correctly you need StudyDate to be of type DateTime
class MyListBoxItem
{
public string StudyBaseFolder { get; set; }
public string StudyName { get; set; }
public string UserLastName { get; set; }
public DateTime StudyDate { get; set; }
}
Then you can order by using LINQ extension methods.
var orderedDirectories =
directories.OrderBy(dir => dir.StudyName)
.ThenBy(dir => dir.StudyDate);
foreach (var directory in orderedDirectories)
{
listBox.Items.Add(directory);
}
You can override .ToString() method in MyListBoxItem class that listbox will display items as you want.
class MyListBoxItem
{
public string StudyBaseFolder { get; set; }
public string StudyName { get; set; }
public string UserLastName { get; set; }
public DateTime StudyDate { get; set; }
public override string ToString()
{
return $"{StudyDate:MMddyyyy}{StudyName}";
}
}
If you can use LINQ in your project, first you should make StudyDate type of DateTime. Then you could do this:
MyList.OrderBy(x => x.StudyName).ThenByDescending(x=>x.StudyDate).ToList()

How to deserialize JSON date time from MongoDB to C# class

I'm using c# driver to interact with mongoDB.
I have a class that I created and which I populate with the data I get from mongoDB.
One of the properties in that class is DateTime.
The value I get from mongo is /\Date(number)/. Which is ok because this is what I'm suppose to return to the client.
The value that I get from mongo after I retrieve the data is ISODate(some number).
I get an exception: "Invalid JSON primitive: ISODate".
How can I configure mongoDB to save the DateTime like I got it i.e. /\Date(number)/?
Sorry L.B - I didn't noticed your answer but went straight to the answer I was given.
Here's the class I'm trying to deserialize:
public class EventDate
{
public EventDate()
{
}
public int? VenueConfigID { get; set; }
public string Category { get; set; }
public DateTime DateAndTime { get; set; }
public string DisplayDate { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public string ShortNote { get; set; }
public string Home { get; set; }
public int? ID { get; set; }
public string Name { get; set; }
}
Here's how I deserialize it:
mongo = MongoServer.Create();
mongo.Connect();
db = mongo.GetDatabase("productionDB");
var col = db.GetCollection<BsonDocument>("eventDates");
var query = Query<PerformerDates>.EQ(ev => ev.PerformerID, performerId);
//MongoCursor<BsonDocument> performer = col.Find(query);
MongoCursor<BsonDocument> performer = col.FindAll();
JavaScriptSerializer js = new JavaScriptSerializer();
List<EventDate> finalMatchedDates = new List<EventDate>();
foreach (var p in performer)
{
//System.Threading.Tasks.Task<EventDate[]> obj2 = JsonConvert.DeserializeObjectAsync<EventDate[]>(p.Elements.ToList()[3].Value.ToString());
EventDate[] obj3 = JsonConvert.DeserializeObject<EventDate[]>(p.Elements.ToList()[3].Value.ToString());
}
mongo.Disconnect();
Solved!!
Eventually I solved it. I used a string instead of a DateTime. When I get it from the DB, I convert it to a DateTime and when I sent it back to the client I serialize it with the format of: /\Date()/
Just use BsonSerializer.Deserialize method.
MongoDB's serializer has a much higher performance over NewtonSoft's Json.Net or Microsoft's DataContractSerializer.
Very common occurring problem! One solution is to use JSON.NET.
See this answer for more help. Although you might be confused with JSON DateTime object but don't worry. It will work!
string json; // Assign JSON here.
var v = Newtonsoft.Json.JsonConvert.DeserializeObjectAsync<T>(json);

How to read stackoverflow rss feed using linq to xml

I am trying read rss feed of stack overflow using Linq to xml. I am unable to get the entry nodes, as it is returning empty list. This I've tried so far, can any one point out what i am doing wrong here?
Here I am binding to the grid view:
private void StackoverflowFeedList()
{
grdFeedView.DataSource = StackoverflowUtils.GetStackOverflowFeeds();
grdFeedView.DataBind();
}
This is the method which will get all feeds:
public static IEnumerable<StackOverflowFeedItems> GetStackOverflowFeeds ()
{
XNamespace Snmp = "http://www.w3.org/2005/Atom";
XDocument RssFeed = XDocument.Load(#"http://stackoverflow.com/feeds");
var posts = from item in RssFeed.Descendants("entry")
select new StackOverflowFeedItems
{
QuestionID = item.Element(Snmp +"id").Value,
QuestionTitle = item.Element(Snmp +"title").Value,
AuthorName = item.Element(Snmp +"name").Value,
CategoryTag = (from category in item.Elements(Snmp +"category")
orderby category
select category.Value).ToList(),
CreatedDate = DateTime.Parse(item.Element(Snmp +"published").Value),
QuestionSummary = item.Element(Snmp +"summary").Value
};
return posts.ToList();
}
And this is the class I am using for binding:
public class StackOverflowFeedItems
{
public string QuestionID { get; set; }
public string QuestionTitle { get; set; }
public IEnumerable<string> CategoryTag { get; set; }
public string AuthorName { get; set; }
public DateTime CreatedDate { get; set; }
public string QuestionSummary { get; set; }
}
You're not using the namespace variable you've declared. Try using
RssFeed.Descendants(Snmp + "entry")
(And likewise for all other places where you're referring to particular names.)
I'm not saying that's necessarily all of what you need to fix, but it's the most obvious problem. You should also consider using the explicit conversions of XElement and XAttribute instead of the Value property, e.g.
CreatedDate = (DateTime) item.Element(Snmp +"published")
I'd also encourage you to pay more attention to indentation, and use pascalCase consistently when naming local variables. (Quite why the namespace variable is called Snmp is another oddity... cut and paste?)

Categories

Resources