Return Multiple Columns in Linq to Sql? - c#

How do I return multiple columns with linq to sql in C#?
I tried to end my query with
select new { A.Product, A.Qty };
but this returns some anonymous type and I am not sure what the heck what to do with this, How to return it and how to extract information out of it. I want to put it in some sort of array.
thanks

Are you trying to return the data from a method?
If so, you should just end the query with select A, which will produce the same type that A is.
If not, you can use the anonymous type the same way you use a regular type.
For example:
var results = from ... select new { A.Product, A.Qty };
foreach(var thing in results) {
Console.WriteLine("{0}: {1}", thing.Product, Thing.Qty);
}
EDIT: To make it into a list, call ToList, like this:
var resultsList = results.ToList();

Call tolist() on the query

Related

Looking for a list of items in a query

I am passing a string list of studentKeys to my LINQ to Entities query.
So I want to return those data that are in that coming list.
public IQueryable<Students> GetStudentsFromKeys(List<string> studentKeys)
{
var result = from a in this.Context.Students
where // ?
return result.ToList();
}
But How should I actually write such a query? I want to query that table and if its keys are the same as one of the keys in that list, return it as a result.
You can do:
var result = from a in this.Context.Students
where studentKeys.Contains(a.StudentKey)
select a;
Or with method syntax as:
var query = this.Context.Students
.Where(r => studentKeys.Contains(r.StudentKey));
(assuming StudentKey is the name of the field you want to compare)
This would generate query similar to
SELECT * from Students WHERE StudentKey in ("1","2","3")

Add new record to linq query result

I have a query as follows:
var paymentInfo =
from i in dbconnect.tblPayments
where i.tenderId == _tenderId
select i;
This query has some results, but I need to add an additional result that I already have, from the variable PaymentInfo.
For example suppose that my query has 2 results i need to add another result to "PaymentInfo" using linq.
I thought that the result is a kind of list, and that I could call .Add(PaymentInfo), but this doesn't work
How can I do this?
You can use Concat to concat another sequence to the end of this one.
var paymentInfo = paymentInfo.Concat(someOtherPayments);
I thought that the result is a kind of list
No, the result is an IEnumerable<T> which is read-only. You can create a list by calling .ToList() and then add an item to it.
var paymentInfo = (from i in dbconnect.tblPayments
where i.tenderId == _tenderId
select i).ToList();
paymentInfo.Add(existingPayment);

How to reuse LINQ subqueries

I am writing a query which contains several join operations. I want to write this query in a function so that I can call this function everytime I need this query. My function and the query are as follows. Since I have several join operations and I don't want to define a complex return type, I keep the return type just IQueryable.
private IQueryable getMySubQuery(MyContext db)
{
var query = db.Orders
.Join( ... )
.Join( ... )
.Join( ... );
return query;
}
public IQueryable <MyType> getData()
{
var db = ...
...
...
var query = getMySubQuery(db)
.Select( /// ERROR ???
return query;
}
I am getting an error: System.Linq.IQueryable doesn't contain a definition for Select.
I understand that if I define the return type of getMySubQuery() method as IQueryable <SomeType>, it will solve the problem. But the problem is I have to define a very complex type containing 50 fields. I don't want to do the projection in getMySubQuery() function. Is there any way I can solve it without creating the complex type? I want to use IQueryable rather than IEnumerable?
If this sample code is truly representative of your actual code then the problem is you're returning an IQueryable, not an IQueryable<T>. The reason you're doing that is because you're trying to use an anonymous type as the result of getMySubQuery, but it's not possible to share anonymous types across method boundaries. If you truly want to do this, you need to create a type that represents the data that is currently being returned as an anonymous type and then make sure you change getMySubQuery to return IQueryable<T> of that type.
Try this: var query = getMySubQuery(db).Tolis()
.Select( /// No ERROR!

Is it possible to format DB content (as string) before comparison with where clause

I'd like to be able to take a url-formatted string (e.g united-kingdom) and use it in a WHERE clause against a Country column that is not formatted in such a way (e.g. United Kingdom).
Ideally, I'd like to be able to do something like this:
db.Jobs
.Where(j => j.Country.MyStringFormattingExtension() == urlformattedstring);
I understand that this is a no go because EF would try and execute the projection on the SQL side. It gives me: "LINQ to Entities does not recognize the method 'System.String MyStringFormattingExtension(System.String)' method, and this method cannot be translated into a store expression."
It has been suggested that I return the query as an enumerable before applying the where clause, however I think that this would be pretty inefficient - returning all rows from the DB before filtering.
You can define a user defined function and import that into your database. Read this article for more details
// In SQL
CREATE FUNCTION dbo.ToFormattedString ...
// In C#
public static class EntityFunctions
{
[EdmFunction("dbo", "ToFormattedString")]
public static string ToFormattedString(this string input)
{
throw new NotSupportedException("Direct calls not supported");
}
}
var results = db.Jobs.Where(j => j.Country.ToFormattedString() == urlFormattedString);
Alternatively, you can create a view in your database that materializes the string the way you want it to be formatted then join it into your Linq query.
// In SQL
CREATE VIEW dbo.vFormattedJobs AS ...
// In C#
var results =
(from j in db.vFormattedJobs
where j.FormattedCountry == urlFormattedString
select j);
How about going the other way, and converting the URL-formatted string into the database format before using it in the query?
var dbFormattedString = urlformattedstring.ConvertToDbFormat();
var result = db.Jobs.Where(j => j.Country == dbFormattedString);
(db.Jobs is already an IEnumerable, so I suppose that the suggestion was to call ToList() on it - it would have worked, but indeed, it would have been very inefficient unless the table is very small.)

Running a simple LINQ query in parallel

I'm still very new to LINQ and PLINQ. I generally just use loops and List.BinarySearch in a lot of cases, but I'm trying to get out of that mindset where I can.
public class Staff
{
// ...
public bool Matches(string searchString)
{
// ...
}
}
Using "normal" LINQ - sorry, I'm unfamiliar with the terminology - I can do the following:
var matchedStaff = from s
in allStaff
where s.Matches(searchString)
select s;
But I'd like to do this in parallel:
var matchedStaff = allStaff.AsParallel().Select(s => s.Matches(searchString));
When I check the type of matchedStaff, it's a list of bools, which isn't what I want.
First of all, what am I doing wrong here, and secondly, how do I return a List<Staff> from this query?
public List<Staff> Search(string searchString)
{
return allStaff.AsParallel().Select(/* something */).AsEnumerable();
}
returns IEnumerable<type>, not List<type>.
For your first question, you should just replace Select with Where :
var matchedStaff = allStaff.AsParallel().Where(s => s.Matches(searchString));
Select is a projection operator, not a filtering one, that's why you are getting an IEnumerable<bool> corresponding to the projection of all your Staff objects from the input sequence to bools returned by your Matches method call.
I understand it can be counter intuitive for you not to use select at all as it seems you are more familiar with the "query syntax" where select keyword is mandatory which is not the case using the "lambda syntax" (or "fluent syntax" ... whatever the naming), but that's how it is ;)
Projections operators, such a Select, are taking as input an element from the sequence and transform/projects this element somehow to another type of element (here projecting to bool type). Whereas filtering operators, such as Where, are taking as input an element from the sequence and either output the element as such in the output sequence or are not outputing the element at all, based on a predicate.
As for your second question, AsEnumerable returns an IEnumerable as it's name indicates ;)
If you want to get a List<Staff> you should rather call ToList() (as it's name indicates ;)) :
return allStaff.AsParallel().Select(/* something */).ToList();
Hope this helps.
There is no need to abandon normal LINQ syntax to achieve parallelism. You can rewrite your original query:
var matchedStaff = from s in allStaff
where s.Matches(searchString)
select s;
The parallel LINQ (“PLINQ”) version would be:
var matchedStaff = from s in allStaff.AsParallel()
where s.Matches(searchString)
select s;
To understand where the bools are coming from, when you write the following:
var matchedStaff = allStaff.AsParallel().Select(s => s.Matches(searchString));
That is equivalent to the following query syntax:
var matchedStaff = from s in allStaff.AsParallel() select s.Matches(searchString);
As stated by darkey, if you want to use the C# syntax instead of the query syntax, you should use Where():
var matchedStaff = allStaff.AsParallel().Where(s => s.Matches(searchString));

Categories