How to convert iqueryable<string> to string in linq? - linq

i have the following code snippet.
in which i just want to return PartyName as a string.
but i get the error:"Cannot implicity convert type 'System.Linq.Iqueryable to string"
if i want to return only string then what to do?
please help me.
return objDatabase.FAPARs
.Where(f => (f.PARTY_CODE == "P003"))
.Select(f => f.PARTY_NAME);

An IQueryable<string> represents a query which could return any number of strings. You want one string - so you need to decide what to do in various situations:
What do you want to happen if the query has no results?
What do you want to happen if the query has one result? (I assume this is simple :)
What do you want to happen if the query has more than one result?
The set of methods which allow you to determine all of this are:
Single - fail if there isn't exactly one result
SingleOrDefault - fail if there's more than one result, return null if there are no results
First - fail if there are no results, return the first of many
FirstOrDefault - return null if there are no results, or the first of many
Last - fail if there are no results, return the last of many
LastOrDefault - return null if there are no results, or the last of many
In each case, "fail" means "throw an exception". (IIRC it's always InvalidOperationException, at least in LINQ to Objects, but I could be wrong.)
So if you're querying by an ID which must exist (i.e. it's a bug if it doesn't) then Single is probably appropriate. If you're querying by an ID which may not exist, then use SingleOrDefault and check whether the return value is null. If you're not querying by an ID, you probably want to use FirstOrDefault or just iterate over the results.
(Note that the default value being null is due to this being a query returning strings, and string being a reference type. In general it's the default value of the element type - so if you had an IQueryable<int>, the default returned would be 0.)

Try
return objDatabase.FAPARs .Where(f => (f.PARTY_CODE == "P003")) .Select(f => f.PARTY_NAME).SingleOrDefault();

Try this:
return objDatabase.FAPARs.Where(f => (f.PARTY_CODE == "P003")).Single(f => f.PARTY_NAME);

return objDatabase.FAPARs.FirstOrDefault(f => f.PARTY_CODE.Equals("P003")).PARTY_NAME

return objDatabase.FAPARs.OfType<FAPAR>()
.Where(f => (f.PARTY_CODE == PartyCode && f.COMP_NO == ComCode))
.Select(f => f.PARTY_NAME).SingleOrDefault();

Related

Laravel query different result between (identical?) two vs three argument 'where' clause

I'm having a very odd issue with a query in laravel (5.2) - I've got a collection created from some external source (an API), and I'm trying to run a 'where' query to extract specific records.
Originally, I was trying to extract all entries which were submitted during the current month (so, after the first day of this month)
$entries is the starting collection (time entries on a project - see end of post)
$thisMonthStart = (new Carbon('first day of this month'))->toDateString();
//value of this is 2017-02-01, and the issue is not resolved if I remove toDateString()
$entriesThisMonth = $entries->where('spent-at', '>', $thisMonthStart);
//returns an empty collection, but should have 15 results
Now the really odd part, is that I tried instead to get $entries where 'spent-at' is equal to the first day of the month - there should be one entry. If I don't explicitly specify the comparison operator, I get my expected result:
$entriesThisMonth = $entries->where('spent-at', $thisMonthStart);
//one $entries returned, see end of post
However if I specify the = operator
$entriesThisMonth = $entries->where('spent-at', '=', $thisMonthStart);
//empty collection returned
So I'm now very confused - presumably something is wrong in my original collection, but why does the specifying vs not specifying the operator make any difference? I would have thought that those two queries would give identical results?
(and obviously, not being able to specify the operator is not very helpful when trying to do a < or > comparison, but I'm mostly just interested in what the actual difference is between those two syntaxes, and so why they give different results?)
I couldn't find any info anywhere on how these two versions of the query work and so if it's expected that they could give different results - I would think that they should be identical, but maybe someone with a deeper understanding could explain what's causing this?
Thank you to anyone who can shed some light on the mystery!
A sample of the $entries collection in case is of any use (just a single record):
(NB there are definitely records from the current month, I know this example is too old)
Collection {#952 ▼
#items: array:367 [▼
175412141 => DayEntry {#958 ▼
#_root: "request"
#_convert: true
#_values: array:16 [ …16]
+"id": "175412141"
+"notes": ""
+"spent-at": "2013-10-03"
+"hours": "0.75"
+"user-id": "595841"
+"project-id": "4287629"
+"task-id": "2448666"
+"created-at": "2013-10-03T18:07:54Z"
+"updated-at": "2013-11-01T12:50:51Z"
+"adjustment-record": "false"
+"timer-started-at": ""
+"is-closed": "false"
+"is-billed": "true"
+"started-at": "10:45"
+"ended-at": "11:30"
+"invoice-id": "3633772"
}
And this is what is returned by the where query without the operator:
Collection {#954 ▼
#items: array:1 [▼
568944822 => DayEntry {#1310 ▼
#_root: "request"
#_convert: true
#_values: array:15 [▶]
+"id": "568944822"
+"notes": "Tweaking formatting on job ads and re shuffling ad order"
+"spent-at": "2017-02-01"
+"hours": "0.25"
+"user-id": "595841"
+"project-id": "4287629"
+"task-id": "2448666"
+"created-at": "2017-02-01T14:45:00Z"
+"updated-at": "2017-02-01T14:45:00Z"
+"adjustment-record": "false"
+"timer-started-at": ""
+"is-closed": "false"
+"is-billed": "false"
+"started-at": "14:30"
+"ended-at": "14:45"
}
]
}
To fix your issue... "returns an empty collection, but should have 15 results". If the collection already exists, you need to filter the results. Something like so:
$thisMonthStart = new Carbon('first day of this month');
$entriesThisMonth = $entries->filter(function ($entry) use ($thisMonthStart) {
return $entry['spent-at'] >= $thisMonthStart;
});
The method illuminate\Support\Collection::where is different to the database collection where, it doesn't take an operator as the second argument.
The where method signature to the collection object you are working with is where(string $key, mixed $value, bool $strict = true)
Your second example with the operator is looking for all elements in the collection that match the string '='.
For further reading on the collection you are working with (not an eloquent collection) look here
To get the 15 results that you are expecting, use the filter method on the collection.
Something along these lines should work:
$entriesThisMonth = $entries->filter (function ($e) use ($thisMonthStart) {
return $e ['spent-at'] > $thisMonthStart;
});

Method Syntax in LINQ: try to use variables in a long query

LINQ newbie here.
I have a long LINQ query, called it MYLONGQUERY, that returns a collection of certain class instances. If the list is not empty, I want to return a property (MYPROPERTY) of the first instance; otherwise it returns some default value (DEFAULTPROPERTY). So the query looks like this
(0 != MYLONGQUERY.count()) ? MYLONGQUERY.FirstOrDefault().MYPROPERTY: DEFAULTPROPERTY
This works fine. However, I don't like the fact that I have to repeat MYLONGQUERY before and after "?". I have been trying Let and Into, but have not been able to get those to work. And it has to be Method Syntax, not Query Syntax. Suggestions? Appreciate it.
You have to select the property first, then you can specify the default-value with DefaultIfEmpty:
var prop = MYLONGQUERY
.Select(x => x.MYPROPERTY)
.DefaultIfEmpty(DEFAULTPROPERTY) // new default-value
.First(); // never exception

querying a list - returns only one value

I have created a structure and list.
public struct CarMake
{
public string name;
public string id;
}
I added structure objects to this (carMakers) and am trying to query
string selCar = from c in carMakers
where c.name == selectedCarMfgName
select c.id;
I am getting an error near select statement- cannont implicity convert IEnumerable to string. I know that query returns only one value, that's why I have like that.
thanks !
string selCar = (from c in carMakers
where c.name == selectedCarMfgName
select c.id).SingleOrDefault();
Your query returns a collection (with one element). You should use Single() (or SingleOrDefault()) to get that one item. If the query can return more than one result, you should look into First() ( or FirstOrDefault())
Pay attention to the error message. It probably says something like
"cannot implicitly convert IEnumerable<string> to string."
The results of a query of a sequence is another sequence, an IEnumerable<T>. You may know that you expect only one result, but that's not what the query does. To obtain only one result, you can optionally include another extension method on the end.
yourQuery.First();
yourQuery.FirstOrDefault();
yourQuery.Single();
yourQuery.SingleOrDefault();
The difference in these is that the First* variations can work with sequenes with many elements, whereas the Single* variations will throw exceptions if more than one element is present. The *OrDefault variations support the concept of no matching elements, and returns the default value for the type (null in the case of classes, a default value (such as 0 for int) for structs).
Use the version that conforms to your expectation. If you expect one and only one match, prefer Single. If you only care about one out of arbitrarily many, prefer First.
carMakers.Add(new CarMake() { name = "Audi", id = "1234" });
string selCar =(from c in carMakers
where c.name == "Audi"
select c.id).FirstOrDefault();
Output- 1234
I would refactor my query slightly:
var selCar = carMakers.Single(c => c.name == selectedCarMfgName).id;
This assumes you know that the car is in the list. If not, use SingleOrDefault and check the return before getting the id.
I've not done too much with LINQ but because you are selecting into a string you may need to use FirstOrDefault as your statement could return back more than one value yet your string can only hold one.
First will return null value I think if nothing is found but FirstOrDefault will return you a blank string.

LINQ - Sequence contains no elements

I am using a LINQ query as below.
object.collection.where(t => t.id.Equals("2")).First();
I am getting the error "Sequence contains no elements". Why does the result throw an error when the result contains no elements? Should it not return null when no results are found? That is what happens when using SQL.
It's working as designed. The First() method is to be called when it's known at least one row will be returned. When this isn't the case, call FirstOrDefault().
object.collection.where(t => t.id.Equals("2")).FirstOrDefault();

LINQ syntax where string value is not null or empty

I'm trying to do a query like so...
query.Where(x => !string.IsNullOrEmpty(x.PropertyName));
but it fails...
so for now I have implemented the following, which works...
query.Where(x => (x.PropertyName ?? string.Empty) != string.Empty);
is there a better (more native?) way that LINQ handles this?
EDIT
apologize! didn't include the provider... This is using LINQ to SQL
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=367077
Problem Statement
It's possible to write LINQ to SQL that gets all rows that have either null or an empty string in a given field, but it's not possible to use string.IsNullOrEmpty to do it, even though many other string methods map to LINQ to SQL.
Proposed Solution
Allow string.IsNullOrEmpty in a LINQ to SQL where clause so that these two queries have the same result:
var fieldNullOrEmpty =
from item in db.SomeTable
where item.SomeField == null || item.SomeField.Equals(string.Empty)
select item;
var fieldNullOrEmpty2 =
from item in db.SomeTable
where string.IsNullOrEmpty(item.SomeField)
select item;
Other Reading:
1. DevArt
2. Dervalp.com
3. StackOverflow Post
This won't fail on Linq2Objects, but it will fail for Linq2SQL, so I am assuming that you are talking about the SQL provider or something similar.
The reason has to do with the way that the SQL provider handles your lambda expression. It doesn't take it as a function Func<P,T>, but an expression Expression<Func<P,T>>. It takes that expression tree and translates it so an actual SQL statement, which it sends off to the server.
The translator knows how to handle basic operators, but it doesn't know how to handle methods on objects. It doesn't know that IsNullOrEmpty(x) translates to return x == null || x == string.empty. That has to be done explicitly for the translation to SQL to take place.
This will work fine with Linq to Objects. However, some LINQ providers have difficulty running CLR methods as part of the query. This is expecially true of some database providers.
The problem is that the DB providers try to move and compile the LINQ query as a database query, to prevent pulling all of the objects across the wire. This is a good thing, but does occasionally restrict the flexibility in your predicates.
Unfortunately, without checking the provider documentation, it's difficult to always know exactly what will or will not be supported directly in the provider. It looks like your provider allows comparisons, but not the string check. I'd guess that, in your case, this is probably about as good of an approach as you can get. (It's really not that different from the IsNullOrEmpty check, other than creating the "string.Empty" instance for comparison, but that's minor.)
... 12 years ago :) But still, some one may found it helpful:
Often it is good to check white spaces too
query.Where(x => !string.IsNullOrWhiteSpace(x.PropertyName));
it will converted to sql as:
WHERE [x].[PropertyName] IS NOT NULL AND ((LTRIM(RTRIM([x].[PropertyName])) <> N'') OR [x].[PropertyName] IS NULL)
or other way:
query.Where(x => string.Compare(x.PropertyName," ") > 0);
will be converted to sql as:
WHERE [x].[PropertyName] > N' '
If you want to go change the type of the collection from nullable type IEnumerable<T?> to non-null type IEnumerable<T> you can use .OfType<T>().
.OfType<T>() will remove null values and return a list of the type T.
Example: If you have a list of nullable strings: List<string?> you can change the type of the list to string by using OfType<string() as in the below example:
List<string?> nullableStrings = new List<string?> { "test1", null, "test2" };
List<string> strings = nullableStrings.OfType<string>().ToList();
// strings now only contains { "test1", "test2" }
This will result in a list of strings only containing test1 and test2.

Resources