I would like to generate an XDocument from my table (the structure is different) but I keep getting the following error :
LINQ to Entities does not recognize the method 'System.String ToString()' method.
I know this is caused by the Birthdate and I would need to use SqlFunctions.StringConvert but I'm working with Framework 4.0
Any ideas on how to solve that?
// Newsletter subscriptions
var news = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("USER",
from n in _dc.Newsletter_Datas
where n.Timestamp >= startDate
select
new XElement("ROW",
new XElement("UTI", n.ID),
new XElement("FIRSTNAME", n.FirstName),
new XElement("FAMILYNAME", n.LastName),
new XElement("GENDER", n.Gender),
new XElement("BIRTHDATE", n.BirthDate != null ? n.BirthDate.Value.ToString("yyyy-MM-dd") : "2003-01-01"),
new XElement("LANGUAGE", n.Language),
new XElement("EMAIL", n.Email),
new XElement("STREETNAME", n.StreetName),
new XElement("HOUSENR", n.HouseNr),
new XElement("BOXNR", n.BoxNr),
new XElement("ZIPCODE", n.Zipcode),
new XElement("CITY", n.City),
new XElement("COUNTRY", n.Country),
new XElement("TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("MESSAGE_ID", "SCNEWS02"),
new XElement("OPT_INS",
new XElement("OPT_IN",
new XElement("OPT_IN_CBP", "01000000000"),
new XElement("OPT_IN_INSERT_TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("OPT_IN_METHOD", "1"),
new XElement("OPT_IN_TYPE", n.OptIn),
new XElement("OPT_IN_CHANNEL", "2"))))));
Thank you very much
Break your query into separate parts, the first part is the query itself. That will be handled by the entity framework. Then cast that query to an IEnumerable<NewsletterData> to finish it off using LINQ to objects. Entity Framework can't do more than a simple projection (which you are clearly not doing).
var query =
from n in _dc.Newsletter_Datas
where n.Timestamp >= startDate
select n;
var news = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("USER",
from n in query.AsEnumerable() // LINQ to objects
select new XElement("ROW",
new XElement("UTI", n.ID),
new XElement("FIRSTNAME", n.FirstName),
new XElement("FAMILYNAME", n.LastName),
new XElement("GENDER", n.Gender),
new XElement("BIRTHDATE", n.BirthDate != null ? n.BirthDate.Value.ToString("yyyy-MM-dd") : "2003-01-01"),
new XElement("LANGUAGE", n.Language),
new XElement("EMAIL", n.Email),
new XElement("STREETNAME", n.StreetName),
new XElement("HOUSENR", n.HouseNr),
new XElement("BOXNR", n.BoxNr),
new XElement("ZIPCODE", n.Zipcode),
new XElement("CITY", n.City),
new XElement("COUNTRY", n.Country),
new XElement("TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("MESSAGE_ID", "SCNEWS02"),
new XElement("OPT_INS",
new XElement("OPT_IN",
new XElement("OPT_IN_CBP", "01000000000"),
new XElement("OPT_IN_INSERT_TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("OPT_IN_METHOD", "1"),
new XElement("OPT_IN_TYPE", n.OptIn),
new XElement("OPT_IN_CHANNEL", "2")
)
)
)
)
);
Related
I want to create a table that list the count of each file type. I've created a query to get that data. When I create the XDocument, how do I execute the query and create rows in the table with data from query?
var query = listFiles.GroupBy(f => Path.GetExtension(f).ToLower())
.Select(g => new
{
Extension = g.Key,
Count = g.Count(),
});
var doc = new XDocument(
new XElement("html",
new XElement("body",
new XElement("table", new XAttribute("border", 2),
foreach (var f in query)
{
new XElement("tr",
new XElement("td", f.Extension),
new XElement("td", f.Count));
}))));
Try following :
var doc = new XDocument(
new XElement("html",
new XElement("body",
new XElement("table", new object[] {
new XAttribute("border", 2),
query.Select(f =>
new XElement("tr",
new XElement("td", f.Extension),
new XElement("td", f.Count)))
}))));
I'll try explain what i'm trying to achieve as best I can...
I'm generating order XML document in C# using XDocument based on data from a SQL Query. Some of the XML Elements & Attributes need only appear once but the Order Line information needs to be looped a number of times; for example if an order contains 3 items I need to generate three instances of the Order Line information, if an order contains 5 items I need to generate five instances of the Order Line information etc.
My XML structure will look like below:
Delivery information - no loop required
Invoice information - no loop required
Order Line information - loop required as per above
More delivery information (shipping type) - no loop required
To get the static information, i'm using a SQLDataReader and passing the information into a variable:
var example = reader["column_name"];
This works fine for when I don't need to loop. However i'm now at the stage where I want to create the loop for Order Line information.
Each Order Line will come as a seperate row in my SQL query, the row will contain all the static information (Delivery information, invoice information etc) as well as the individual Order Line information (SKU, Product Description etc).
Essentially what I think I need to do is a foreach loop for each row in the SQLDataReader, and populate variables to drop into the XML OrderLine section, however I'm not sure how to do this, nor is this the best approach.
I can create a static version of the OrderLine section easily enough, but how would I go about looping through the SQL rows to pass variables into it? My static OrderLine code is as below
new XElement("OrderLine", new XAttribute("TypeDescription", "Goods & Services"), new XAttribute("Action", "Add"), new XAttribute("TypeCode", "GDS"),
new XElement("LineNumber", new XAttribute("Preserve", "true"), "item_number then increment by 1"),
new XElement("Product",
new XElement("SuppliersProductCode", "VALUE"),
new XElement("Description", "VALUE")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("Amount", "Value")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("UnitPrice", "Value"))),
My full XML generate code looks like this:
new XElement("Order",
new XElement("OrderHead",
new XElement("Schema",
new XElement("Value", "3.05")),
new XElement("Parameters",
new XElement("Language", "en-GB"),
new XElement("DecimalSeperator", "."),
new XElement("Precision", "12.3")),
new XElement("OrderType", new XAttribute("Code", "PUO"), "Purchase Order"),
new XElement("OrderCurrency",
new XElement("Currency", new XAttribute("Code", "GBP"), "GB Pounds Sterling"))),
new XElement("OrderReferences",
new XElement("BuyersOrderNumber", new XAttribute("Preserve", "true"), incrementid_var)),
new XElement("Buyer",
new XElement("BuyerReferences",
new XElement("SupplierscodeForBuyer", "****VALUE****")),
new XElement("Contact",
new XElement("Name"))),
new XElement("Delivery",
new XElement("DeliverTo",
new XElement("Party", firstname_var + " " + lastname_var),
new XElement("Contact",
new XElement("Name", firstname_var + " " + lastname_var),
new XElement("Email", "****EMAIL ADDRESS****")),
new XElement("Address",
new XElement("AddressLine", street_var),
new XElement("AddressLine", city_var),
new XElement("AddressLine", region_var),
new XElement("PostCode", postcode_var),
new XElement("Country", new XAttribute("Code", countryid_var)))),
new XElement("DeliverFrom",
new XElement("Party", firstname_var + " " + lastname_var))),
new XElement("InvoiceTo",
new XElement("Party", firstname_var + " " + lastname_var),
new XElement("Address",
new XElement("AddressLine", street_var),
new XElement("AddressLine", city_var),
new XElement("AddressLine", region_var),
new XElement("PostCode", postcode_var),
new XElement("Country", new XAttribute("Code", countryid_var)))),
//Start Loop
new XElement("OrderLine", new XAttribute("TypeDescription", "Goods & Services"), new XAttribute("Action", "Add"), new XAttribute("TypeCode", "GDS"),
new XElement("LineNumber", new XAttribute("Preserve", "true"), "item_number then increment by 1"),
new XElement("Product",
new XElement("SuppliersProductCode", "VALUE"),
new XElement("Description", "VALUE")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("Amount", "Value")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("UnitPrice", "Value"))),
// End Loop
//Start Delivery Information
new XElement("OrderLine", new XAttribute("TypeDescription", "VALUE"), new XAttribute("Action", "VALUE"), new XAttribute("TypeCode", "VALUE"),
new XElement("LineNumber", new XAttribute("Preserve", "true"), "item_number + 1"),
new XElement("Product",
new XElement("SuppliersProductCode", "**** DELIVERY CODE ****"),
new XElement("Description", "**** DELIVERY DESCRIPTION****")),
new XElement("Quantity", new XAttribute("UOMDescription", "Piece"), new XAttribute("UOMCode", "PCE"),
new XElement("Amount", "1")),
new XElement("Quantity", new XAttribute("UOMDescription", "Pack"), new XAttribute("UOMCode", "PCK"),
new XElement("UnitPrice", "0"))),
new XElement("AdditionalOrderReferences",
new XElement("OrderReference", incrementid_var)),
new XElement("DeliveryInformation", "TELEPHONE NUMBER")));
Everything outside of the Start Loop, End Loop comments only needs to be generated once. If the order has 5 items I need to generate the code within those comments 5 times.
Any help is much appreciated as i'm going round in circles reading articles and still not sure how to implement this.
Thanks
Iain
I am fairly new to LINQ and XML and am trying to work with an existing large 500k line XML file which has the same structure as the XML below. I have figured out how to test for multiple null XElements but am totally stuck on how to search for multiple Identical XElements.
How do I get LINQ to return just contacts that work for google?
Thank you all in advanced.
void Main()
{
XDocument AddressBook = CreateAddressBookXML();
var query =
from contact in AddressBook.Descendants("Contact")
let companyelement = contact.Element("Company")
where companyelement != null
let companyname = companyelement.Descendants("CompanyName")
where companyname != null && companyname == "Google"
select contact;
Console.Write(query);
}
public XDocument CreateAddressBookXML() {
XDocument result =
new XDocument(
new XComment("My phone book"),
new XElement("phoneBook",
new XComment("My friends"),
new XElement("Contact",
new XAttribute("name", "Ralph"),
new XElement("homephone", "555-234-4567"),
new XElement("cellphone", "555-345-75656"),
new XElement("Company",
new XElement("CompanyName","Ralphs Web Design"),
new XElement("CompanyName","Google")
)
),
new XElement("Contact",
new XAttribute("name", "Dave"),
new XElement("homephone", "555-756-9454"),
new XElement("cellphone", "555-762-1546"),
new XElement("Company",
new XElement("CompanyName","Google")
)
),
new XComment("My family"),
new XElement("Contact",
new XAttribute("name", "Julia"),
new XElement("homephone", "555-578-1053"),
new XElement("cellphone", "")
),
new XComment("My team"),
new XElement("Contact",
new XAttribute("name", "Robert"),
new XElement("homephone", "555-565-1653"),
new XElement("cellphone", "555-456-2567"),
new XElement("Company",
new XElement("CompanyName","Yahoo")
)
)
)
);
return result;
}
var query = from contacts in CreateAddressBookXML().Root.Descendants("Contact")
where contacts.Element("Company") != null &&
contacts.Element("Company").Elements("CompanyName").
FirstOrDefault(c => c.Value == "Google") != null
select contacts;
I generally prefer to mix in a bit of XPath to write these queries, it's far more compact than the LINQ equivalent.
var query =
from contact in doc.XPathSelectElements("/phoneBook/Contact")
where contact.XPathSelectElements("Company/CompanyName[.='Google']").Any()
select contact;
Otherwise, using LINQ:
var query =
from contact in doc.Elements("phoneBook").Elements("Contact")
where contact.Elements("Company").Elements("CompanyName")
.Any(c => (string)c == "Google")
select contact;
I get an HybridDictionary with all the child XElements.
I don't know ahead how many items I have there.
So instead of doing this:
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
new XElement("Id", "796"),
new XElement("Name", "gdsa")
etc..
));
I'm trying to do something like that:
Strung [] allKeys = new String[ChildElements.Count];
TheHybridDictionary.Keys.CopyTo(allKeys, 0);
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
for (int i = 0; i < TheHybridDictionary.Count; i++)
new XElement(allKeys[i], TheHybridDictionary[allKeys[i]])
But how to connect whatever is inside the for loop to be part of the XML document construction?
Problem is, your HybridDictionary class does not implement IEnumerable, so you can't use LINQ on it directly.
But you can use allKeys string array instead:
string [] allKeys = new String[ChildElements.Count];
TheHybridDictionary.Keys.CopyTo(allKeys, 0);
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
allKeys.Select(x => new XElement(x, TheHybridDictionary[x])))
You can use .Add() method as in Stefan's comment, or use LINQ:
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
TheHybridDictionary.Select(kvp => new XElement(kvp.Key, kvp.Value)));
I can use XDocument to build the following file which works fine:
XDocument xdoc = new XDocument
(
new XDeclaration("1.0", "utf-8", null),
new XElement(_pluralCamelNotation,
new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
),
new XElement(_singularCamelNotation,
new XElement("id", "2"),
new XElement("whenCreated", "2008-12-31")
)
)
);
However, I need to build the XML file by iterating through a collection like this:
XDocument xdoc = new XDocument
(
new XDeclaration("1.0", "utf-8", null));
foreach (DataType dataType in _dataTypes)
{
XElement xelement = new XElement(_pluralCamelNotation,
new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
));
xdoc.AddInterally(xelement); //PSEUDO-CODE
}
There is Add, AddFirst, AddAfterSelf, AddBeforeSelf, but I could get none of them to work in this context.
Is an iteration with LINQ like this possible?
Answer:
I took Jimmy's code suggestion with the root tag, changed it up a bit and it was exactly what I was looking for:
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement(_pluralCamelNotation,
_dataTypes.Select(datatype => new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
))
)
);
Marc Gravell posted a better answer to this on this StackOverflow question.
You need a root element.
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("Root",
_dataTypes.Select(datatype => new XElement(datatype._pluralCamelNotation,
new XElement(datatype._singlarCamelNotation),
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
))
)
);
If I'm not mistaken, you should be able to use XDocument.Add():
XDocument xdoc = new XDocument
(
new XDeclaration("1.0", "utf-8", null));
foreach (DataType dataType in _dataTypes)
{
XElement xelement = new XElement(_pluralCamelNotation,
new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
));
xdoc.Add(xelement);
}
I know it's very very old post but I stumbled across this today trying to solve the same problem. You have to add the element to the Root of the document:
xdoc.Root.Add(xelement);
What's wrong with the simple Add method?