I have the following XML. What is the best way to get the data?
<?xml version='1.0' encoding='UTF-8'?>
<Root>
<EmployeeDataRoot>
<EmployeeData>
<Employee_id>123456</Employee_id>
<Employee_Status>A</Employee_Status>
<Business_Unit>EN00</Business_Unit>
<Cost_Center>0904/1992</Cost_Center>
<Work_Location>DFW</Work_Location>
<Location>DFW-HDQ1</Location>
<Job_Category>0003</Job_Category>
<Last_Name>John</Last_Name>
<First_Name>Doe</First_Name>
<Middle_Name />
<Preferred_Name />
<Position_Title>Programmer/Analyst</Position_Title>
<Legal_Entity>EN00</Legal_Entity>
<Department_Unit>IT HR & Employee Technology</Department_Unit>
<Run_Date>2016-12-12</Run_Date>
</EmployeeData>
</EmployeeDataRoot>
<Footer_No_of_Records>
<Records>1</Records>
</Footer_No_of_Records>
</Root>
After looking at some examples online, I tried these two iterations but get an error
object not set to an instance of an object
I looked over the properties of my Employee class as well as the Nodes for any misspellings and didn't see any. I think the error is that I'm not querying the XML properly.
var xDoc = XDocument.Load(file.FullName);
listEmployee =
(from e in xDoc.Descendants("EmployeeData")
select new Employee
{
EmployeeID = e.Element("Employee_ID").Value,
EmployeeStatus = e.Element("Employee_Status").Value,
BusinessUnit = e.Element("Business_Unit").Value,
CostCenter = e.Element("Cost_Center").Value,
WorkLocation = e.Element("Work_Location").Value,
Location = e.Element("Location").Value,
JobCategory = e.Element("Job_Category").Value,
FirstName = e.Element("First_Name").Value,
LastName = e.Element("Last_Name").Value,
LegalEntity = e.Element("Legal_Entity").Value
}
).ToList();
and I also tried
listEmployee =
(from e in xDoc.Element("Root").Elements("EmployeeDataRoot/EmployeeData")
select new Employee
{
EmployeeID = e.Element("Employee_ID").Value,
EmployeeStatus = e.Element("Employee_Status").Value,
BusinessUnit = e.Element("Business_Unit").Value,
CostCenter = e.Element("Cost_Center").Value,
WorkLocation = e.Element("Work_Location").Value,
Location = e.Element("Location").Value,
JobCategory = e.Element("Job_Category").Value,
FirstName = e.Element("First_Name").Value,
LastName = e.Element("Last_Name").Value,
LegalEntity = e.Element("Legal_Entity").Value
}
).ToList();
Your attempt, ist right, but you write "Employee_ID" wrong. Try this out:
var xDoc = XDocument.Load(file.FullName);
listEmployee =
(from e in xDoc.Descendants("EmployeeData")
select new Employee
{
EmployeeID = e.Element("Employee_id").Value,
EmployeeStatus = e.Element("Employee_Status").Value,
BusinessUnit = e.Element("Business_Unit").Value,
CostCenter = e.Element("Cost_Center").Value,
WorkLocation = e.Element("Work_Location").Value,
Location = e.Element("Location").Value,
JobCategory = e.Element("Job_Category").Value,
FirstName = e.Element("First_Name").Value,
LastName = e.Element("Last_Name").Value,
LegalEntity = e.Element("Legal_Entity").Value
}
).ToList();
Related
Im using DTO's in EntityFrameWork with WebApi 2.0 , so I want to retrieve all the Orders, within the Orders, OrderProducts is a list in my program, I want to retrieve all the OrderProducts related to that Order my code right now is the following:
public async Task < IHttpActionResult > GetOrder() {
var order = from x in db.Order
select new OrderDTO {
OrderId = x.OrderId,
UserId = x.UserId,
orderStatusCode = x.orderStatusCode,
OrderProducts = new List < OrderProductDTO > {
new OrderProductDTO {
OrderId = x.OrderProducts.Select(y = >y.OrderId).FirstOrDefault(),
OrderProductId = x.OrderProducts.Select(y = >y.OrderProductId).FirstOrDefault(),
ProductId = x.OrderProducts.Select(y = >y.ProductId).FirstOrDefault(),
Product = new ProductDTO() {
productDesc = x.OrderProducts.Select(y = >y.Product.productDesc).FirstOrDefault(),
ProductId = x.OrderProducts.Select(y = >y.Product.ProductId).FirstOrDefault(),
productName = x.OrderProducts.Select(y = >y.Product.productName).FirstOrDefault(),
productPrice = x.OrderProducts.Select(y = >y.Product.productPrice).FirstOrDefault(),
}
}
},
purchaseDate = x.purchaseDate,
quantityOrder = x.quantityOrder,
totalOrderPrice = x.totalOrderPrice,
User = new UserDTO {
UserId = x.UserId,
username = x.User.username,
userInfo = new UserInfoDTO {
adress = x.User.UserInfo.adress,
city = x.User.UserInfo.city,
country = x.User.UserInfo.country,
zip = x.User.UserInfo.zip
}
}
};
return Ok(order);
Everything appears to be ok, but when I call the WebApi only the first element is returned, not all the elements in OrderProduct:
Any idea how to retrieve all the OrderProducts? Thanks.
Well you're only populating a single item in your query. Instead, you should do this:
....
OrderProducts = x.OrderProducts.Select(op => new OrderProductDTO
{
OrderId = op.OrderId,
OrderProductId = op.OrderProductId,
//etc
}
....
It looks like you're only asking for one Product instead of a List
Product = new ProductDTO() {
productDesc = x.OrderProducts.Select(y = >y.Product.productDesc).FirstOrDefault(),
ProductId = x.OrderProducts.Select(y = >y.Product.ProductId).FirstOrDefault(),
productName = x.OrderProducts.Select(y = >y.Product.productName).FirstOrDefault(),
productPrice = x.OrderProducts.Select(y = >y.Product.productPrice).FirstOrDefault(),
}
Should probably be
Products = new List<ProductDTO>() {...}
In the below code, I have a collection of Employee object. I have to check whether the employee are InOrg or not. For that I do a left join with the InOrgCatalog table and return an anonymous object. I already have an InOrg property
in my Employee object, so instead of returning an anonymous object I want to return the Employee object with the InOrg property updated. What change I have to do in the query to achieve that?
List<Employee> employees = new List<Employee>
{
new Employee { EmployeeId = 1, EmployeeName = "Aaron" , Alias = "AWERAS", InOrg = false},
new Employee { EmployeeId = 2, EmployeeName = "asdfsdf" , Alias = "HJKHJK", InOrg = false},
new Employee { EmployeeId = 3, EmployeeName = "qwerwe" , Alias = "NMUIYUI", InOrg = false},
new Employee { EmployeeId = 4, EmployeeName = "zcvcx" , Alias = "PIOUKJ", InOrg = false},
};
using (var context = new MyDbContext())
{
var result = (from employee in employees
join catalog in context.InOrgCatalogs on new { Alias = employee.Alias, Active = true } equals
new { Alias = catalog.Alias, Active = catalog.Active }
into ps
from p in ps.DefaultIfEmpty()
select new { Employee = employee , InOrg = !(p == null)}).ToList();
}
it looks to me you need to select a new Employeee object rather than an anonymous object. Then you can update the properties as needed:
using (var context = new MyDbContext())
{
var result = (from Employee employee in employees
join catalog in context.InOrgCatalogs on new { Alias = employee.Alias, Active = true } equals
new { Alias = catalog.Alias, Active = catalog.Active }
into ps
from p in ps.DefaultIfEmpty()
select new Employee { EmployeeId = employee.EmployeeId,EmployeeName = employee.EmployeeName, Alias = employee.Alias, InOrg = !(p == null) }).ToList();
}
Also you can use trick with let keyword and double assigning:
using (var context = new MyDbContext())
{
var result = (from employee in employees
join catalog in context.InOrgCatalogs
on new { Alias = employee.Alias, Active = true } equals
new { Alias = catalog.Alias, Active = catalog.Active } into ps
from p in ps.DefaultIfEmpty()
let temp = employee.InOrg = (p != null)//it will do the work
select employee).ToList();
}
I have a Collection of Data and the Dictionary:
Collection handle Student Data
Dictionary Keeps Student Courses.
I want to get the Course Name from the Dictionary and put it into as CourseName.
private viod GenerateStudentDetails(Student studentData)
{
var courses = m_courses.GetCoursesDictionary(); // returns Dictionary<Guid,string>()
var studentDetails= from data in studentData
select new
{
FirstName = data.FirstName,
LastName = data.LastName,
Email = data.Email,
Mobile = data.Profile.Mobile,
City = data.Profile.City,
PostCode = data.Profile.PostCode,
CourseName = courses[data.Profile.CourseID ?? Guid.Empty]
};
}
"LINQ to Entities does not recognize the method 'System.String get_Item(System.Guid)' method, and this method cannot be translated into a store expression."
You could try something as the below:
private viod GenerateStudentDetails(Student studentData)
{
var courses = m_courses.GetCoursesDictionary(); // returns Dictionary<Guid,string>()
var studentDetails= (from data in studentData
select new
{
FirstName = data.FirstName,
LastName = data.LastName,
Email = data.Email,
Mobile = data.Profile.Mobile,
City = data.Profile.City,
PostCode = data.Profile.PostCode,
CourseID = data.Profile.CourseID
}).AsEnumerable()
.Select(item=>new
{
FirstName = item.FirstName,
LastName = item.LastName,
Email = item.Email,
Mobile = item.Profile.Mobile,
City = item.Profile.City,
PostCode = item.Profile.PostCode,
CourseName = courses[item.Profile.CourseID ?? Guid.Empty]
});
}
What's the problem?
The problem is that the last expression in the anonymous type you create,
CourseName = courses[data.Profile.CourseID ?? Guid.Empty]
cannot be in this place, because it can't be translated appropriately. So you have this option. You can declare a sequence of the data you want from the studentData and then make any conversion of call anything you want to the new anonymous type we create.
Just for thought
var eCourses = ((IEnumerable<KeyValuePair<Guid, string>>) courses);
var studentDetails = (from data in studentData
select new
{
data.FirstName,
data.LastName,
data.Email,
data.Profile.Mobile,
data.Profile.City,
data.Profile.PostCode,
CourseName = eCourses.FirstOrDefault(s => s.Key == data.Profile.CourseID).Value
});
<?xml version="1.0" standalone="yes"?>
<CompanyInfo>
<Employee name="Jon" deptId="123">
<Region name="West">
<Area code="96" />
</Region>
<Region name="East">
<Area code="88" />
</Region>
</Employee>
</CompanyInfo>
public class Employee
{
public string EmployeeName { get; set; }
public string DeptId { get; set; }
public List<string> RegionList {get; set;}
}
public class Region
{
public string RegionName { get; set; }
public string AreaCode { get; set; }
}
I am trying to read this XML data, so far I have tried this:
XDocument xml = XDocument.Load(#"C:\data.xml");
var xElement = xml.Element("CompanyInfo");
if (xElement != null)
foreach (var child in xElement.Elements())
{
Console.WriteLine(child.Name);
foreach (var item in child.Attributes())
{
Console.WriteLine(item.Name + ": " + item.Value);
}
foreach (var childElement in child.Elements())
{
Console.WriteLine("--->" + childElement.Name);
foreach (var ds in childElement.Attributes())
{
Console.WriteLine(ds.Name + ": " + ds.Value);
}
foreach (var element in childElement.Elements())
{
Console.WriteLine("------->" + element.Name);
foreach (var ds in element.Attributes())
{
Console.WriteLine(ds.Name + ": " + ds.Value);
}
}
}
}
This enables me to get each node, its attribute name and value and so I can save these data into the relevant field in database, but this seems a long winded way and
not flexible, for instance if the XML structure changes all those foreach statements needs revisiting, also it is difficult to filter the data this way,
I need to write certain if statements to filter the data (e.g get employees from West only etc...)
I was looking for a more flexible way, using linq, something like this:
List<Employees> employees =
(from employee in xml.Descendants("CompanyInfo")
select new employee
{
EmployeeName = employee.Element("employee").Value,
EmployeeDeptId = ?? get data,
RegionName = ?? get data,
AreaCode = ?? get data,,
}).ToList<Employee>();
But I am not sure how I can get the values from the child nodes and apply the filtering (to get the certain employees only). Is this possible? Any help is appreciated.
Thanks
var employees = (from e in xml.Root.Elements("Employee")
let r = e.Element("Region")
where (string)r.Attribute("name") == "West"
select new Employee
{
EmployeeName = (string)e.Attribute("employee"),
EmployeeDeptId = (string)e.Attribute("deptId"),
RegionName = (string)r.Attribute("name"),
AreaCode = (string)r.Element("Area").Attribute("code"),
}).ToList();
But it will still require query revision when XML file structure changes.
Edit
Query for multiple regions per employee:
var employees = (from e in xml.Root.Elements("Employee")
select new Employee
{
EmployeeName = (string)e.Attribute("employee"),
DeptId = (string)e.Attribute("deptId"),
RegionList = e.Elements("Region")
.Select(r => new Region {
RegionName = (string)r.Attribute("name"),
AreaCode = (string)r.Element("Area").Attribute("code")
}).ToList()
}).ToList();
You can then filter the list for employees from given region only:
var westEmployees = employees.Where(x => x.RegionList.Any(r => r.RegionName == "West")).ToList();
You can track the structure:
from employee in xml
.Element("CompanyInfo") // must be root
.Elements("Employee") // only directly children of CompanyInfo
or less strictly
from employee in xml.Descendants("Employee") // all employees at any level
And then get the information you want:
select new Employee
{
EmployeeName = employee.Attribute("name").Value,
EmployeeDeptId = employee.Attribute("deptId").Value,
RegionName = employee.Element("Region").Attribute("name").Value,
AreaCode = employee.Element("Region").Element("Area").Attribute("code").Value,
}
And with the additional info about multiple regions, assuming a List<Region> Regions property:
select new Employee
{
EmployeeName = employee.Attribute("name").Value,
EmployeeDeptId = employee.Attribute("deptId").Value,
//RegionName = employee.Element("Region").Attribute("name").Value,
//AreaCode = employee.Element("Region").Element("Area").Attribute("code").Value,
Regions = (from r in employee.Elements("Region") select new Region
{
Name = r.Attribute("name").Value,
Code = r.Element("Area").Attribute("code").Value,
}).ToList();
}
You can do the selection in one query and then the filtering in second or combine them both to one query:
Two queries:
// do te transformation
var employees =
from employee in xml.Descendants("CompanyInfo").Elements("Employee")
select new
{
EmployeeName = employee.Attribute("name").Value,
EmployeeDeptId = employee.Attribute("deptId").Value,
Regions = from region in employee.Elements("Region")
select new
{
Name = region.Attribute("name").Value,
AreaCode = region.Element("Area").Attribute("code").Value,
}
};
// now do the filtering
var filteredEmployees = from employee in employees
from region in employee.Regions
where region.AreaCode == "96"
select employee;
Combined one query (same output):
var employees2 =
from selectedEmployee2 in
from employee in xml.Descendants("CompanyInfo").Elements("Employee")
select new
{
EmployeeName = employee.Attribute("name").Value,
EmployeeDeptId = employee.Attribute("deptId").Value,
Regions = from region in employee.Elements("Region")
select new
{
Name = region.Attribute("name").Value,
AreaCode = region.Element("Area").Attribute("code").Value,
}
}
from region in selectedEmployee2.Regions
where region.AreaCode == "96"
select selectedEmployee2;
But there is one little thing you should consider adding. For robustness, you need to check existence of your elements and attributes then the selection will look like that:
var employees =
from employee in xml.Descendants("CompanyInfo").Elements("Employee")
select new
{
EmployeeName = (employee.Attribute("name") != null) ? employee.Attribute("name").Value : string.Empty,
EmployeeDeptId = (employee.Attribute("deptId") != null) ? employee.Attribute("deptId").Value : string.Empty,
Regions = (employee.Elements("Region") != null)?
from region in employee.Elements("Region")
select new
{
Name = (region.Attribute("name")!= null) ? region.Attribute("name").Value : string.Empty,
AreaCode = (region.Element("Area") != null && region.Element("Area").Attribute("code") != null) ? region.Element("Area").Attribute("code").Value : string.Empty,
}
: null
};
what is the wrong with this LINQ statement:
(from deposit in DAOBase<CashBookDeposit, long>.GetIQueryableBusinessBase()
where deposit.Id == id
select new CashBookDeposit
{
Id = deposit.Id,
DepositeNumber = deposit.DepositeNumber,
DocumentTypeName = deposit.CashBookDepositDocumentType.EnglishName,
StatusName = deposit.CashBookDepositeStatus.EnglishName,
CashbookName = deposit.CashBook.EnglishName,
Collector = deposit.Collector,
Partner = deposit.Partner,
CashBookDepositDocumentType = deposit.CashBookDepositDocumentType,
CreationDate = deposit.CreationDate,
PaidAmount = deposit.TotalAmount,
Description = deposit.Description,
TempReceipts = (from receipt in deposit.TempReceipts
select new TempReceipt
{
Id = receipt.Id,
Code = receipt.Code,
ReceiptNo = receipt.ReceiptNo,
Amount = receipt.Amount,
BusinessPartnerName = receipt.Partner.ENName,
CollectorName = receipt.Collector.EnglishName,
StatusName = receipt.TempReceiptStatus.EnglishName,
CollectionDate = receipt.CollectionDate,
CreationDate = receipt.CreationDate,
Description = receipt.Description,
}).ToList()
}).SingleOrDefault();
i got this exception :
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
need help, thanks
You can change the query as follows:
(from deposit in DAOBase<CashBookDeposit, long>.GetIQueryableBusinessBase()
let receipts = (from tempReceipts in deposit.TempReceipts
select tempReceipts)
where deposit.Id == id
select new CashBookDeposit
{
Id = deposit.Id,
DepositeNumber = deposit.DepositeNumber,
DocumentTypeName = deposit.CashBookDepositDocumentType.EnglishName,
StatusName = deposit.CashBookDepositeStatus.EnglishName,
CashbookName = deposit.CashBook.EnglishName,
Collector = deposit.Collector,
Partner = deposit.Partner,
CashBookDepositDocumentType = deposit.CashBookDepositDocumentType,
CreationDate = deposit.CreationDate,
PaidAmount = deposit.TotalAmount,
Description = deposit.Description,
TempReceipts = (from receipt in receipts
select new TempReceipt
{
Id = receipt.Id,
Code = receipt.Code,
ReceiptNo = receipt.ReceiptNo,
Amount = receipt.Amount,
BusinessPartnerName = receipt.Partner.ENName,
CollectorName = receipt.Collector.EnglishName,
StatusName = receipt.TempReceiptStatus.EnglishName,
CollectionDate = receipt.CollectionDate,
CreationDate = receipt.CreationDate,
Description = receipt.Description,
}).ToList()
}).SingleOrDefault();