Using WCF RIA I have a query that returns a Query of names
public class WitnessInfo
{
[Key]
public Guid WCFId { get; set; }
public string witnessName { get; set; }
public string AllNames {get; set;}
}
Here's my Linq Query
[Query]
public IQueryable<WitnessInfo> getWitnessInfo(int? id)
{
IQueryable<WitnessInfo> witnessQuery = from witness in this.Context.witness
where witness.DAFile.Id == id
select new WitnessInfo
{
WCFId = Guid.NewGuid(),
witnessName = witness.Person.FirstName,
};
return witnessQuery;
}
I want to take all the names and return them in a single string i.e "John, James, Tim, Jones". Tried taking AllNames and looping through but that didn't work. Any suggestions?
First grab all of the information that you need in a single query, then use String.Join to map the collection of names to a single string:
var firstQuery = from witness in Context.witness
where witness.DAFile.Id == id
select new
{
WCFId = Guid.NewGuid(),
witnessName = witness.Person.FirstName,
Names = Context.witness.Select(w => w.FirstName),
})
.AsEnumerable(); //do the rest in linq to objects
var finalQuery = from witness in firstQuery
//do the string manipulation just once
let allNames = string.Join(", ", witness.Names)
select new WitnessInfo
{
WCFId = witness.WCFId,
witnessName = witness.witnessName,
AllNames = allNames,
});
By having the AllNames property in the WitnessInfo class, it is seems like you want each WitnessInfo object to contain the all of the squence names again and again repeatedly, and if this is your case then do it like that:
var names = (from witness in this.Context.witness
select witness.Person.FirstName).ToArray();
var allNames = string.Join(", ", names);
IQueryable<WitnessInfo> witnessQuery = from witness in this.Context.witness
where witness.DAFile.Id == id
select new WitnessInfo
{
WCFId = Guid.NewGuid(),
witnessName = witness.Person.FirstName,
AllNames = allNames
};
You can concatenate like this:
string.Join(", ", getWithnessInfo(666).Select(wq => wq.witnessName))
this.Context.witness.Select(a => a.Person.Firstname).Aggregate((a, b) => a + ", " + b);
Related
Upon completeing the tutorial here:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
I currently use the following
userAccesses = userAccesses.Where(s => s.employeeDetail.employeeNumber.ToUpper().Contains(searchValue.ToUpper()));
However I'd like to concatenate the knownas / surname columns and then do the contains on the concatenated items.
Could anyone explain/suggest an example syntax?
This is what I've attempted below but I'm certain my syntax is incorrect.
userAccesses = userAccesses.Where(s => s.employeeDetail.employeeNumber + " " + s.employeeDetail.knownas + " " + s.employeeDetail.surname).Contains(searchValue);
Thanks for the response everyone, final working version is below.
userAccesses.Where(x => (x.employeeDetail.employeeNumber + x.employeeDetail.knownas + x.employeeDetail.surname).Contains(searchValue));
You should go to this direction
public class Employee
{
public string knownas { get; set; }
public string userName { get; set; }
}
public void Test()
{
List<Employee> employess = new List<Employee>();
string searchvalue = "test";
var listEmplyer = employess.Where(x => (x.userName + x.knownas).Contains(searchvalue));
}
You'll simply need to concatenate the string and call Contains on that string.
userAccesses
.Where(s => $"{s.employeeDetail.employeeNumber} {s.employeeDetail.knownas} {s.employeeDetail.surname}".Contains(searchValue))
If you need an enumerable of strings as the result of the expression, you can also choose to use the following:
userAccesses
.Select(s => $"{s.employeeDetail.employeeNumber} {s.employeeDetail.knownas} {s.employeeDetail.surname}")
.Where(s => s.Contains(searchValue))
Searching through concatenated column values is weird...
I'd suggest smth like this:
var filtered = userAccesses.Where(s => s.employeeDetail.employeeNumber.Contains(searchValue)
|| s.employeeDetail.knownas.Contains(searchValue)
|| s.employeeDetail.surname.Contains(searchValue));
I want to define the character that is written.
I think it would be easier to explain by giving an example.
sample;
void Main(){
List<account> account = new List<UserQuery.account>{
new account() { accountCode = "100", accountName = "That is the house which I want. " },
new account() { accountCode = "101", accountName = "I bought whatever you wanted" },
new account() { accountCode = "102", accountName = "The flowers which you brought me were very beautiful."}
};
string search = "*house*";
string search2 = "The flowers*";
string search3 = "*wanted.";
var result = account.FirstOrDefault(a => a.accountName.Contains(search)).accountCode;
var result2 = account.FirstOrDefault(a => a.accountName.StartsWith(search2)).accountCode;
var result3 = account.FirstOrDefault(a => a.accountName.EndsWith(search3)).accountCode;
}
public class account
{
public string accountCode { get; set; }
public string accountName { get; set; }
}
> result=100
result2=102
result3=101
This is how I search for star characters.
You are looking for wildcards which you can turn into corresponding *regular expressions, see
Matching strings with wildcard
E.g.
private static String WildCardToRegular(String value) {
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}
Then operate with regular expression as usual:
using System.Text.RegularExpressions;
...
var result = account
.FirstOrDefault(a => Regex.IsMatch(a.accountName, WildCardToRegular(search)))
.accountCode; //TODO: what if the outcome of FirstOrDefault is null?
var result2 = account
.FirstOrDefault(a => Regex.IsMatch(a.accountName, WildCardToRegular(search2)))
.accountCode;
var result3 = account
.FirstOrDefault(a => Regex.IsMatch(a.accountName, WildCardToRegular(search3)))
.accountCode;
Please, notice that there's no need in StartsWith, Contains, EndsWith when working with wild cards
Edit: if you want a value matched all you need is to modify the query:
var accountFound = account
.Select(a => a.accountName)
.SelectMany(acc => Regex
.Matches(acc, WildCardToRegular(search))
.OfType<Match>()
.Where(match => match.Success)
.Select(match => match.Value))
.FirstOrDefault();
I have an existing method of generating a list of every operators. I would like to modify it, to only display operators who are not in a so called 'Inactive' role- this information comes from OperatorType table, column: Role
The existing code:
public static List<TPPROperatorDetails> GetOperators()
{
return DataHelper.DbTPPRTracer.TPPROperators.Select(
op => new TPPROperatorDetails{
Id = op.Id,
FullName = op.Name,
UserName = op.UserName,
Designation = op.Position,
OperatorTypes = ParseOperatorType(op.UserType),
SignatureImage = op.SignatureImage
}).ToList();
}
You can use the Where method. Something like this
public static List<TPPROperatorDetails> GetOperators()
{
return DataHelper.DbTPPRTracer.TPPROperators
.Where(op => ParseOperatorType(op.UserType) == "Inactive")
.Select(
op => new TPPROperatorDetails{
Id = op.Id,
FullName = op.Name,
UserName = op.UserName,
Designation = op.Position,
OperatorTypes = ParseOperatorType(op.UserType),
SignatureImage = op.SignatureImage
})
.ToList();
}
<?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
};
I am trying to delete rows from a table using where column in (collection) using the following method:
public void DeleteRows(int parentId, List<int> years)
{
var yearsAsCommaSeperatedString = ListToCommaSeperatedString(years);
const string query = "DELETE FROM TABLE t WHERE t.PARENT_ID=:Parent AND t.YEAR in(:yearList)";
Session
.CreateSQLQuery(query)
.SetParameter("Parent", parentId)
.SetParameter("yearList", yearsAsCommaSeperatedString)
.ExecuteUpdate();
}
private static string ListToCommaSeperatedString(IEnumerable<int> ints)
{
var aggregate = ints.Aggregate("", (current, i) => current + (i + ", "));
return aggregate.Substring(0, aggregate.LastIndexOf(",", StringComparison.Ordinal));
}
The problem is that yearsAsCommaSeperatedString is a string, therefor the db can not interpret it the numbers. I've also tried adding the list of integers as the parameter, but NHibernate does not know what to do with it.
How can i use where in(collection) with CreateSQLQuery?
You can use something like this
ISession session = GetSession();
string hql = #"from Product p
where p.Category in (:categories)";
var categoriesToSearch = new[] {new Category {Id = 1}, new Category {Id = 2}};
var query = session.CreateQuery(hql);
query.SetParameterList("categories", categoriesToSearch);
var products = query.List<Product>();
Or you can try this
public void DeleteRows(int parentId, List<int> years)
{
const string query = "DELETE FROM TABLE t WHERE t.PARENT_ID=:Parent AND t.YEAR in (:yearList)";
Session
.CreateSQLQuery(query)
.SetParameter("Parent", parentId)
.SetParameterList("yearList", years)
.ExecuteUpdate();
}
If your Method works, you can use the SetParamter again, but must change the SQL-Query to the follow:
var yearsAsCommaSeperatedString = ListToCommaSeperatedString(years);
const string query = "DELETE FROM TABLE t WHERE t.PARENT_ID=:Parent AND t.YEAR in(\":yearList\")";
Session .CreateSQLQuery(query)
.SetParameter("Parent", parentId)
.SetParameter("yearList", yearsAsCommaSeperatedString)
.ExecuteUpdate();
Should be better than string concatenation (sql-injection) :)
Greetings