Parsing text file containing hierarchical items using linq - c#

I'm rewriting some code and trying to use Linq whenever I can. My problem right now is a simple file import function.
The file basically looks like this:
A1
B1|1882
C1|7315808907578
B9
B1|1883
C1|4025595431639
C1|8717734091786
C1|8717734091809
C1|8717734098280
C1|8717795041874
C1|8717795060998
C1|8717795108973
B9
B1|1884
C1|4025595732071
C1|7315808887184
C1|8717734001983
B9
A9
The existing code looks like this:
line = reader.ReadLine();
string itemNo = "";
List<AltItems> list = new List<AltItems>();
while (line != null) {
posts = line.Split(postSep);
if (posts.Length == 0) { }
else if (posts[0].Equals("A1")) { }
else if (posts[0].Equals("B1"))
itemNo = posts[1];
else if (posts[0].Equals("C1")) {
string altItemNo = posts[1];
list.Add(new AltItems() { ItemNo = itemNo, AltItemNo = altItemNo });
}
line = reader.ReadLine();
}
What would the equivalent Linq query look like? Any thoughts about performance penalties rewriting this code using Linq? I also have files with multiple hierarchical levels where data from items on the first level is needed to build up items on the third level...

I would agree with Ahmed ilyas. Rewriting everything in LINQ does not mean it would work faster.
Especially, regarding string parsing, you should know that it is not supported in LINQ. This is absolutely reasonable if you think that LINQ is a query language targeting data sources of many kinds in a unified way. There are ways to do it, but they are always too indirect and I don't particularly like them. One of them, is using Scott Guthry's DynamicLinq library, the way it suggested here.
Please note that I only show you a way to do string parsing using LINQ. This does not mean that I would suggest using LINQ to replace conditional code.
Hope I helped!

Related

ASP.NET/C# - Entity Framework - Classes - Skeleton Method

I currently have a Class which uses the function as such:
var txbl = test.search_bustype("SUP", "Name");
or
foreach(string toWorkWith in test.search_bustype("SUP", "Name")){ // each one }
However, for every Column I want to search using a function, I have to create a separate function.
ie: Columns - bustype, companyID - Would have to have separate functions to search.
My current code is:
public Array search_bustype(string match, string forthat)
{
db = new rkdb_07022016Entities2();
var tbl = (from c in db.tblbus_business select c).ToArray();
List<string> List = new List<string>();
int i = 0;
foreach (var toCheck in tbl)
{
if (toCheck.BusType.ToString() == match)
{
if (forthat == "Name")
{
List.Add(toCheck.Name);
}
}
i++;
}
return List.ToArray();
}
Is there anyway to possibly, like php actually send the query to the function and then run it there? I haven't been able to find many sources about how to build a secure infrastructure with Entity so I am wondering if anyone knows any way of maybe creating a skeleton method with this framework.
Thanks in advance!
Okay so I stumbled on the Frameworks sources and actually now understand that the Framework itself implements the Skeleton method.
You simply only refer to each query inside the (from c in......
I'll have to look further into how this infrastructure works before I can understand how to further implement functions.
Thank-you for your time however! I will close this.

Entity Framework query table name dynamically based on input parameter

I have been working in a project which uses Entity Framework as the ORM data model to connect to the SQL database and retrieve data.
Now the basic query which is used to retrieve data is like this
ProjectDataContext dataContext = new ProjectDataContext();
var result = (from project in dataContext.Projects
select project).ToList();
Or in lambda
List<Project> lstprojects = dataContext.Projects.Take(10);
Now I would like to pass the table name dynamically based on some input parameter. How can I achieve that?
The way I am currently doing it is a bit messy.
if(tableName = "A")
{
List<A> lstOfA = dataContext.A.Take(10);
}
else if(tableName = "B")
{
List<B> lstOfB = dataContext.B.Take(10);
}
and so on...
My question is if there is a neat and clean way to do this without writing so many if else because I understand it may cause performance issues in future.
Thanks
Ok after some trial and error I have been able to do it like this-
var type = Type.GetType("A");
context.Set(type).Load();
var result = context.Set(type).Local.Cast<object>().ToList();
Hope it helps.`

how to use LINQ to find an object in csv file

Hy,
I have a csv file like that
user_name1,c:\photo\user_photo.jpg,0,0,0,0
in which every line refers a distinct object with own fileds separated from comma.
How I find a particular object knowing the user name? I use distinct user_names. And after that how I make that object, curent object that I use?
What i have done until now:
StreamReader sc = new StreamReader(#"C:\Player.csv");
String linie = sc.ReadLine();
while (!String.IsNullOrEmpty(linie))
{
string[] stringu = linie.Split(',');
Player player = new Player(stringu[0], stringu[1], int.Parse(stringu[2]), int.Parse(stringu[3]), int.Parse(stringu[4]));
players.Add(player);
linie = sc.ReadLine();
}
sc.Close();
var query = players.Where(a => a.Name == label6.Text);
}
Sincerly,
You could try to use a library, which makes easy the use of CSV files with LINQ queries. Please look here.
Firstly I'd suggest that for parsing a CSV file you don't roll your own field splitter. I'd suggest using something like the TextFieldParser (which can be used in C# by referencing Microsoft.VisualBasic).
Once you've created the parser you can use it to get the array of strings for each record represented by line in your application:
List<Players> players = new List<Players>();
var parser = new TextFieldParser();
while ( !parser.EOF )
{
string [] playerFields = parser.ReadFields();
// Create player from fields
var player = Player.FromFields(playerFields);
players.Add(player);
}
Now it really depends on whether you want to continuously query the players in the file, as if you do then getting an in-memory copy and using LINQ makes sense, else if you only want to query once then I'd simply do the check line by line.
Assuming that you do want to query multiple times then parsing the file and holding the values in a List or similar makes sense (assuming the file isn't ridiculously big).
Finally, if you has distinct user names then you could use the FirstOrDefault method in LINQ to give you the single player back that matches.
var player = players.FirstOrDefault(p => p.Name.Equals(textBox.Text));
Or if you know that you have unique player names you could just store the whole lot in a dictionary....?
if ( players.ContainsKey(textBox.Text) )
{
var player = players[textBox.Text];
}
Anyway, just some thoughts.
The only problem you have at the moment, as far as I can see, it that you say you are looking to fetch "a particular object", but in your last line you are using Where which is going to return an IEnumerable containing one, none or many such objects. If you want to fetch one uniquely named object you should use Single or SingleOrDefault, e.g.
var myPlayer = players.Single(x => x.Name == label6.Text);
The answer you have accepted has merely converted your query from method syntax to the equivalent query syntax and introduced a compilation error by attempting to convert the resulting IEnumerable<Player> to a Player.
In anticipation of a problem you may be about to have, you might also want to look into Microsoft.VisualBasic.FileIO.TextFieldParser (you'll need to add a reference to Microsoft.VisualBasic.dll), which will allow you to parse a CSV in a more robust way, i.e. handle fields containing commas etc., using something like the following:
using (var parser = new TextFieldParser(filename))
{
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
var p = parser.ReadFields();
players.Add(new Player(p[0], p[1], int.Parse(p[2]), int.Parse(p[3]), int.Parse(p[4])));
}
}
Have you tried something like
Player selected_player = from pl in players
where pl.Name == label6.Text
select pl;
?

Linq to XML: Queries for If blocks C#

I've got XML set up like this
<customers>
<customer id="1">
<name title="Mr" first="John" last="Smith" />
<contact number="07123123123" email="john.smith#johnsmith.com" />
<address postcode="E1 1EW">1 Paper Street, London, England, GB</address>
</customer>
(...)
</customers>
I'm trying to query it with Linq to XML for learning purposes. So far I can XDocument.Load the file fine and add/remove etc. But I can't seem to figure out a way to query my XML documents for use in an if block. for example something like (Pseudo code):
XDocument document = XDocument.Load("People.xml");
if(
exists(
document.customers.customer.name.first.value("john")
&& document.customers.customer.name.last.value("smith")
)
)
{
bool exists = true;
}
Whatever I try something the compiler will either laugh at me or spit out something about how it cannot implicitly convert an Ienumerable bool to a bool.
I've been trying many combinations of things from many different google searches for a while now and I think guessing is starting to do more harm than good, can anybody provide a C# snippet that would work in an if block for my xml setup? Just to see if first and last name exist together in the same node. Usually once I see something actually work I can take it from there. Most of the questions I find on the net are only searching to see if the entire node exists or are only searching for one attribute and I just can't seem to tailor it.
(Before anybody bursts into flames over my XML structure, this is not for production purposes, I just want to get a grasp of using this in case I need to in an upcoming project.)
Bonus love for anybody that can link any documentation that's not MSDN (I already have about 10 tabs open on it) and involves some good low level/beginner tutorials on Linq to XML.
To check for John Smith exists as a customer in your XML you ll use
XDocument doc = XDocument.Load(Path);
var customers = doc.Descendants("customer");
//To Check for John Smith
if (customers.Elements("name")
.Any(E => E.Attribute("first").Value == "John"
&& E.Attribute("last").Value == "Smith"))
{
//Do your thing
}
Created a boolean called check to hold the result.
do a count on how many elements called name have attributes First=john and last=smith
Then set the result to check variable.
BTW your XML was missing a " in front of John. That will cause you problems :)
bool check;
var res = XDocument.Load(#"c:\temp\test.xml");
var results = res.Descendants("name")
.Where(x => x.Attribute("first").Value == "john" && x.Attribute("last").Value == "smith")
.Select(x => x.Elements()).Count();
check = results != 0;
XPath is your friend
using System.Xml.XPath;
...
void foo(){
XDocument document = XDocument.Load("People.xml");
var firstCustomerNode = document.XPathSelectElement(
"/customers/customer[0]/name"
);
var hasfirstNameAndLastName = firstCustomerNode.Attribute("firstname") != null && firstCustomerNode.Attribute("lastname") != null;
if(hasfirstNameAndLastName)
{
}
}
Please note that you may also use a schema to validate your Xml, but it's more complex to write.
If you don't want to use XPath, you may also write:
var firstCustomerNode = document.Root.Element("Customers").Elements("customer").First().Element("name");
But honestly, the XPath query is far more readable, and will simplify the error check. This code suppose all the elements up to the target node exists. If not, your code will fail with a poor NullReferenceException.
You need to start by querying the Document.Root.Descendants. Then a method such as IfExists
var nodes = document.Root.Descendants("customer");
bool IfExists(string FirstName, string LastName) {
return nodes.Elements("name").Any(node =>
node.Attribute("first").Value.Equals(FirstName) &&
node.Attribute("last").Value.Equals(LastName));
}
You may want to add exception handling in case an attribute is missing or contains an empty value.

Dynamic LINQ in c#

Hey i am making a simple search machine through alot of different coloumns in 2 tables.
I was trying to get this to abit dynamical.
I read this:
Is there a pattern using Linq to dynamically create a filter?
Which is something that really could do the trick for me.. its just in VB and i need it in c#
here is my code :
private void displayWith1Criteria(string column, string value)
{
Console.WriteLine("entering _1_ display method");
dbcontent = new DBtestEntities();
var studienummerQuery = from members in dbcontent.Medlemmer.Include("Retninger")
where column == value
orderby members.Fornavn
select new { Studienr = members.Studienummer, Fornavn = members.Fornavn, Efternavn = members.Efternavn, Email = members.Email, Studiested = members.Studiested, Betaling = members.BetalingsType, Uddannelses_Retning = members.Retninger.retningNavn };
dataGridView1.DataSource = studienummerQuery;
}
Doesn't return any data at all...
column is being called with members.Fornavn (Fornavn - a column name)
value = Anders (one of the data's in Fornavn column)
What I want to do:
My database is loaded into dbcontent using a .edmx file from ABO entity class.
My database consist of 2 tables, "Retninger" and "Medlemmer".
Medlemmer contains columns things like Fornavn(in english, Firstname), Efternavn(Lastname), Studienummer(study no.)
What i would like is a "dynamic" method that can set both which column to be searched in and the value that needs to be searched for in the set column.
When could your expression column == value possibly return true? Only if string.Equals("Fornavn", "Anders") is true.
Doing dynamic linq is hard. Is usually do it this way:
...
where (!useMycolumn1 || member.mycolumn1 == value1)
&&(!useMycolumn2 || member.mycolumn2 == value2)
&&(!useMycolumn3 || member.mycolumn3 == value3)
...
useMycolumn* is a local boolean variable which is set to true or false, depending on whether the certain condition should be tested or not. This way, unused parts of the query are optimized out at compile time.
I think this answer from Shawn Miller to the question you linked is more what you are looking for:
http://www.albahari.com/nutshell/predicatebuilder.html
Are you remembring to call the DataBind() method on the grid? How do you know nothing is being returned?
I think its because of lazy evaluation of LINQ queries.
You can try using .ToList, as below:
dataGridView1.DataSource = studienummerQuery.ToList();
also .DataBind(), if relevant for your object.
Edit:
Lazy Evaluation: This Link, would serve as a good start

Categories

Resources