In this question, if I need to get "date" included in the output, what changes should be made?
When I included
let dt = l.Element("Date").Value
It gives, "Object reference not set to an instance of an object"
var query = from l in doc.Descendants("L1")
let dt = l.Element("Date").Value
let id = l.Attribute("id").Value
from subject in l.Descendants("Subject")
select new
{
Date = dt,
Id = id,
SubjectName = (string)subject.Attribute("SubjectName"),
Score = (string)subject.Attribute("Score")
};
foreach (var result in query)
{
Console.WriteLine(result);
}
If l doesn't have an Date element, trying to access l.Element("Date").Value will incur an error. You can use a conditional:
var query = from l in doc.Descendants("L1")
let dt = l.Elements("date").Any()
? l.Element("date").Value
: AnyDefaultValueIWantForDate
let id = l.Attribute("id").Value
from subject in l.Descendants("Subject")
select new
{
Date = dt,
Id = id,
SubjectName = subject.Attribute("SubjectName").Value,
Score = subject.Attribute("Score").Value
};
(I also added the .Value in SubjectName and Score).
Looking at your other XML, it does not, as Mr. Skeet mentioned, have anything in the <date> elements. You will need to explicitly handle that if you aren't planning on always having data in there.
You can do something like this:
let dt = l.Element("date") == null ? string.Empty : l.Element("date").Value
Assuming l is not null then l.Element("Date") is null which would mean that one or more of your L1 elements does not have a child Date element.
The fix would depend on what you want to do with missing dates. If you want to use default(DateTime) as a "magic" date, you could do:
let dt = (l.Element("Date") == null ? default(DateTime) : l.Element("Date").Value)
Related
I use System.Linq.Dynamic to query entities with dynamic 'where' expressions. I'm querying object that has property "newValue" of string type. Exemplary value would be : "{\"ProcessId\":764, \"ProcessLength\":1000}".
I can't use == because I want to find all hits where the property contains "ProcessId:764", regardless on the rest of the string. The thing is, that stored string contains escape sign "\" and double quotes and I can't figure out what it should like exactly..
dbContext.Processes.Where("#newValue.Contains(\"ProcessId\":764\")") brings error, however dbContext.Processes.Where("#newValue.Contains(\":764\")") works correctly. I guess it must be something with backslashes or double quotes in my query but can't figure it out on my own..
There are two things to note here:
If you know at compile time the column that should be queried (i.e., newValue), just use standard Linq: var list = items.Where(i => i.NewValue.Contains("904")).ToList().
If you do want to use dyanmic Linq, What you'd usually want is to apply Where on some column, e.g. Where("SomeColumn.Contains("something")"), or Where("SomeColumn.Contains(#0)", new string[] {"something"}).
So, in your case, this should work: items.Where("newValue.Contains(\"904\")").
Doing Where("#newValue.Contains("something")") doesn't really make sense, since #newValue would be parsed as a string literal. See also this comment on a similiar question.
Here' a quick example:
public static void Main(string[] args)
{
var items = new []
{
new { Id = "1", Title = "ProcessId: 123"},
new { Id = "4", Title = "ProcessId: 456"},
new { Id = "7", Title = "ProcessId: 789"},
}.ToList();
// returns null, because the string "Title" doesn't contain the string "7"
var res1 = items.Where("#0.Contains(\"7\")", new string[] {"Title"}).FirstOrDefault();
// works - returns the 3rd element of the array
var res2a = items.Where("Title.Contains(#0)", new string[] {"ProcessId: 789"}).FirstOrDefault();
var res2b = items.Where("Title.Contains(\"ProcessId: 789\")").FirstOrDefault();
}
#HeyJude Thanks for the effort, but I still can't get it to work. It has somehow gone wronger and now I can't even fetch correct rows giving only ProcessId number..
Let me give you more detailed description of my setup. In the database there's a table with column "NewValue", I use this column to store json string of current (for the time of creating row in the table) representation of some object e.g. object Process. So the column stores for example string of {"ProcessId":904,"ProcessLength":1000}. To fetch this data from db I create collection of table's records: var items = (from l in db.JDE_Logs
join u in db.JDE_Users on l.UserId equals u.UserId
join t in db.JDE_Tenants on l.TenantId equals t.TenantId
where l.TenantId == tenants.FirstOrDefault().TenantId && l.Timestamp >= dFrom && l.Timestamp <= dTo
orderby l.Timestamp descending
select new //ExtLog
{
LogId = l.LogId,
TimeStamp = l.Timestamp,
TenantId = t.TenantId,
TenantName = t.TenantName,
UserId = l.UserId,
UserName = u.Name + " " + u.Surname,
Description = l.Description,
OldValue = l.OldValue,
NewValue = l.NewValue
});. Then I query it to find matching rows for given ProcessId number e.g. query = "#NewValue.Contains(\"904,)\")";
items = items.Where(query);
This should fetch back all records where NewValue column contains the query string, but this doesn't work. It compiles and 'works' but no data are fetched or fetched are only those records where 904 appears later in the string. Sounds stupid but this is what it is.
What should the query string look like to fetch all records containing "ProcessId":904?
I have the problem in where condition please check this
<Uni_Details Uni_ID="U001" User_Mode="New">
<Uni_Name>
<Full_Name>Asian</Full_Name>
<Short_Name />
</Uni_Name>
<Asc_Uni>
<Asc_Details Asc_Name="Stafford">
<Asc_Add>fsfadfsdfsdfsdf</Asc_Add>
<Asc_Tel>+44 34234234234</Asc_Tel>
<Asc_Country>United Kingdom</Asc_Country>
<Asc_Web>www.ac.lk</Asc_Web>
</Asc_Details>
</Asc_Uni>
<Branch>
<Branch_Details Branch_Name="Head Office">
<Branch_Add>dasdasdadsd</Branch_Add>
<Branch_City>Colombo</Branch_City>
<Branch_Country>Sri Lanka</Branch_Country>
<Branch_Tel>+94 342432423</Branch_Tel>
</Branch_Details>
<Branch_Details Branch_Name="Access Tower">
<Branch_Add>dfgdfgdfgdf</Branch_Add>
<Branch_City>Colombo</Branch_City>
<Branch_Country>Sri Lanka</Branch_Country>
<Branch_Tel>+94 342432453</Branch_Tel>
</Branch_Details>
</Branch>
<Uni_EMail>info#apiit.lk</Uni_EMail>
<Uni_Web>www.apiit.lk</Uni_Web>
<Course_Data>
<Course_Details Course_ID="U001C001">
<Course_Name>Computer Course</Course_Name>
<Course_Qual>Pass O/L</Course_Qual>
<Course_Dur>3 Months</Course_Dur>
<Course_Content>
<Course_Conent_List>C#.net</Course_Conent_List>
<Course_Conent_List>VB.Net</Course_Conent_List>
<Course_Conent_List>Design Practices</Course_Conent_List>
</Course_Content>
<Course_Fee>
<Fee_Amount Amount_Currency="SL Rs.">5000.00</Fee_Amount>
<Fee_Comment>Onwards</Fee_Comment>
</Course_Fee>
<Course_Desc>Learn Basic Programming practices</Course_Desc>
<Course_Next>Next October</Course_Next>
<Category_List>
<Cat_ID>2</Cat_ID>
<Cat_ID>1</Cat_ID>
</Category_List>
</Course_Details>
</Course_Data>
</Uni_Details>
<Uni_Details Uni_ID="U002" User_Mode="New">
<Uni_Name>
<Full_Name>American College</Full_Name>
<Short_Name>AC</Short_Name>
</Uni_Name>
<Asc_Uni>
<Asc_Details Asc_Name="American College USA">
<Asc_Add>fasdfsdfsdfsdsdfs</Asc_Add>
<Asc_Tel>+94 112 230623</Asc_Tel>
<Asc_Country>United States</Asc_Country>
<Asc_Web>www.ac.lk</Asc_Web>
</Asc_Details>
</Asc_Uni>
<Branch>
<Branch_Details Branch_Name="Head Office">
<Branch_Add>FFSDFASDFSDF</Branch_Add>
<Branch_City>Colombo</Branch_City>
<Branch_Country>Sri Lanka</Branch_Country>
<Branch_Tel>+94 112 230623</Branch_Tel>
</Branch_Details>
</Branch>
<Uni_EMail>info#ac.lk</Uni_EMail>
<Uni_Web>www.ac.lk</Uni_Web>
<Course_Data>
<Course_Details Course_ID="U002C0001">
<Course_Name>Computer Course</Course_Name>
<Course_Qual>O/L Pass</Course_Qual>
<Course_Dur>3 Months</Course_Dur>
<Course_Content>
<Course_Conent_List>C#.net</Course_Conent_List>
<Course_Conent_List>VB.Net</Course_Conent_List>
<Course_Conent_List>Design Practices</Course_Conent_List>
</Course_Content>
<Course_Fee>
<Fee_Amount Amount_Currency="SL Rs.">5000</Fee_Amount>
<Fee_Comment></Fee_Comment>
</Course_Fee>
<Course_Desc>Basics</Course_Desc>
<Course_Next>Next October</Course_Next>
<Category_List>
<Cat_ID>1</Cat_ID>
</Category_List>
</Course_Details>
<Course_Details Course_ID="U002C0002">
<Course_Name>Accounting Course</Course_Name>
<Course_Qual>O/L Pass</Course_Qual>
<Course_Dur>6 Months</Course_Dur>
<Course_Content>
<Course_Conent_List>Accounts Basics</Course_Conent_List>
<Course_Conent_List>Business Studies</Course_Conent_List>
<Course_Conent_List>Acc Pack</Course_Conent_List>
</Course_Content>
<Course_Fee>
<Fee_Amount Amount_Currency="SL Rs.">10000</Fee_Amount>
<Fee_Comment></Fee_Comment>
</Course_Fee>
<Course_Desc>Basic Accounting</Course_Desc>
<Course_Next>Next January</Course_Next>
<Category_List>
<Cat_ID>3</Cat_ID>
<Cat_ID>2</Cat_ID>
</Category_List>
</Course_Details>
</Course_Data>
</Uni_Details>
this is my XML file I need to retrieve all data which cat_id is 1
var data = (from cats in data_file.Elements("Uni_Data").Elements("Uni_Details")
where cats.Element("Course_Data").Element("Course_Details").Element("Category_List").Element("Cat_ID").Value == cat_id.ToString()
select new
{
uni_name = cats.Element("Uni_Name").Element("Full_Name").Value.ToString(),
uni_short = cats.Element("Uni_Name").Element("Short_Name").Value.ToString(),
price = cats.Element("Course_Data").Element("Course_Details").Element("Course_Fee").Element("Fee_Amount").Value.ToString()
});
however this works if I have cat_id 1 as my first element if its in second place it won't listed so plz help me with this
The problem is with the way the end of your where clause is setup: Element("Cat_ID").Value == cat_id.ToString().
Specifically, the Element("Cat_ID") part will check the first child "Cat_ID" element. So if Cat_ID 1 is the second item, it won't be found. Instead, you need to check all child elements for a match.
var data = (from cats in data_file.Elements("Uni_Data").Elements("Uni_Details")
let catId = cats.Element("Course_Data").Element("Course_Details").Element("Category_List").Elements("Cat_ID").FirstOrDefault(c => c.Value == cat_id.ToString())
where catId != null
select new
{
uni_name = cats.Element("Uni_Name").Element("Full_Name").Value.ToString(),
uni_short = cats.Element("Uni_Name").Element("Short_Name").Value.ToString(),
price = cats.Element("Course_Data").Element("Course_Details").Element("Course_Fee").Element("Fee_Amount").Value.ToString()
});
The query uses a let clause to store the result of the FirstOrDefault call, which uses the predicate to match the criteria. Next, if it isn't null then the rest of the query works as before. If it's null it means no match was found.
That said, your query has a lot of repeated elements. It also uses .Value.ToString() in a few places, which is redundant since the Value property already returns a string. I would clean up the query as follows:
var data = from cats in data_file.Elements("Uni_Data").Elements("Uni_Details")
let uniName = cats.Element("Uni_Name")
let details = cats.Element("Course_Data").Element("Course_Details")
let catId = details.Element("Category_List").Elements("Cat_ID").FirstOrDefault(c => c.Value == cat_id.ToString())
where catId != null
select new
{
uni_name = uniName.Element("Full_Name").Value,
uni_short = uniName.Element("Short_Name").Value,
price = details.Element("Course_Fee").Element("Fee_Amount").Value
};
I am trying o set textboxes on an ASP.NET webpage using LINQ - SQL. Here is the code I have to perform the select statement:
EQCN = Request.QueryString["EQCN"];
var equipment = from n in db.equipments
where n.EQCN.ToString() == EQCN
select n;
How do I set TextBox1.text to be a specific field in the table?
Thanks so much
EDIT
I need to output every field in the table into different textboxes. So performing a query for ever single one seems a little much. There has to be a way to do this?
Thanks
Well you can select the appropriate field to start with:
EQCN = Request.QueryString["EQCN"];
var values = from n in db.equipments
where n.EQCN.ToString() == EQCN
select n.FieldYouWant;
// Or possibly Single, or First...
var singleValue = values.FirstOrDefault();
I think that's what you were after, but if it's not, please clarify your question.
EDIT: To answer your follow-up, you can use:
EQCN = Request.QueryString["EQCN"];
var query = from n in db.equipments
where n.EQCN.ToString() == EQCN
select n;
// Or possibly Single, or First...
var entity = query.Single();
textBox1.Text = entity.Name;
textBox2.Text = entity.Description;
textBox3.Text = entity.Title;
// etc
That's assuming you want to have access to everything in the entity. If the entity is very large and you only need a few fields, you might want to do something like this:
EQCN = Request.QueryString["EQCN"];
var query = from n in db.equipments
where n.EQCN.ToString() == EQCN
select new { n.Name, n.Description, n.Title };
// Or possibly Single, or First...
var projection = query.Single();
textBox1.Text = projection.Name;
textBox2.Text = projection.Description;
textBox3.Text = projection.Title;
I'm not sure I'd actually couple the data access and UI layers so closely, but that's a different matter...
You only need to perform the query once, but once that's done, you'll have to assign each field to a TextBox. Start by retrieving only the single item you want:
EQCN = Request.QueryString["EQCN"];
var equipment = (from n in db.equipments
where n.EQCN.ToString() == EQCN
select n).FirstOrDefault();
Then go through and assign each TextBox to the appropriate field:
txtName.Text = equipment.Name;
txtDescription.Text = equipment.Description;
txtValue1.Text = equipment.Value1;
txtValue2.Text = equipment.Value2;
//...
If you have several dozen TextBoxes to assign, you could set up a custom control that can be databound to an equipment object, but even then, you'll still have to write the binding code for your control.
The only way I can think of to totally automate this process is to name each TextBox after a field in your object, then use reflection to match them to values:
var textboxes = Panel1.Controls.OfType<TextBox>();
foreach (TextBox txt in textboxes)
{
string fieldname = txt.ID.Remove(0, 3); //"txtDescription" becomes "Description"
string value = equipment.GetType().GetProperty(fieldname).GetValue(equipment, null) as string;
txt.Text = value;
}
Importing a spreadsheet I have filled a DataTable object with that data and returns expected results.
Attempting to put this into a format I can easily query to search for problem records I have done the following
public void Something(DataTable dt)
{
var data = from row in dt.AsEnumerable()
select row["Order"].ToString();
}
Works as expected giving me a list of orders. However I cannot add other fields to this EnumerableRowCollection. Attempting to add other fields as follows gives me an error
public void Something(DataTable dt)
{
// row["Version"] throws an error on me
var data = from row in dt.AsEnumerable()
select row["Order"].ToString(), row["Version"].ToString();
}
Error: "A local variable named 'row' cannot be declared in this scope because it would give a different meaning to 'row' which is already used in a 'child' scope to donate something else"
I'm thinking I need to alias the column name but I'm having no luck. What am I missing here?
It sounds like you're writing a bad select statement. Try the following:
public void Something(DataTable dt)
{
var data = from row in dt.AsEnumerable()
select new {
Order = row["Order"].ToString(),
Something = row["Something"].ToString(),
Customer = row["Customer"].ToString(),
Address = row["Address"].ToString()
};
}
That will create a new collection of Anonymously Typed objects that you can iterate over and use as needed. Keep in mind, though, that you want be able to return data from the function. If you need that functionality, you need to create a concrete type to use (in place of anonymous types).
I think you should use select new like this query for example:
var q = from o in db.Orders
where o.Products.ProductName.StartsWith("Asset") &&
o.PaymentApproved == true
select new { name = o.Contacts.FirstName + " " +
o.Contacts.LastName,
product = o.Products.ProductName,
version = o.Products.Version +
(o.Products.SubVersion * 0.1)
};
You probably want the following.
var data = from row
in dt.AsEnumerable()
select new { Order = row["Order"].ToString(), Version = row["Version"].ToString() };
I have a requirement to extract a distinct subset of rows from a DataTable, and thought LINQ2DataSets may be a useful and clean way to do this, however it appears that it is not possible to simply identify return rows from a LINQ2DS query as follows
var result = from r in fips.AsEnumerable() select
r.Field<string>("FACILITY_PROCESS_SUB_GROUP_CODE"),
r.Field<string>("PROCESS_SUB_GROUP_NAME"),
r.Field<string>("...
as I start getting errors after the first comma.
Is this a correct assumption, and how would I get around it to return a subset of columns from the dataset that I can apply a Distinct() method to?
You forgot the new statement and field names:
var result = from r
in fips.AsEnumerable()
select new
{
FacProcess = r.Field<string>("FACILITY_PROCESS_SUB_GROUP_CODE"),
GroupName = r.Field<string>("PROCESS_SUB_GROUP_NAME"),
Item3 = r.Field<string>("Item3")
};
You can also explicitly declare that you are going to use a type:
var result = from r
in fips.AsEnumerable()
select new MyType("InitClassParams")
{
FacProcess = r.Field<string>("FACILITY_PROCESS_SUB_GROUP_CODE"),
GroupName = r.Field<string>("PROCESS_SUB_GROUP_NAME"),
Item3 = r.Field<string>("Item3")
};
Scott Guthrie (VP Developer Devision, Microsoft) has some good info about LINQ (he talks about LINQ to SQL, but most of it applies regardless).
Then apply the distinct clause:
var result = from r
in fips.AsEnumerable()
select new
{
FacProcess = r.Field<string>("FACILITY_PROCESS_SUB_GROUP_CODE"),
GroupName = r.Field<string>("PROCESS_SUB_GROUP_NAME"),
Item3 = r.Field<string>("Item3")
}
distinct;
Then put it to a list or iterate over it. Nothing will be selected/distincted/etc until something like on of the following is run:
var list = result.ToList()
foreach(var item in result) {}