Linq: Handle empty table - linq

How do you handle an empty table/NullReference in LINQ?
I have the following Linq statement in my code:
List<FeaturedTrack> features = _db.FeaturedTracks.Where(f => (f.FeatureStartDate >= DateTime.Now && f.FeatureEndDate <= DateTime.Now) ||
(f.FeatureStartDate == null && f.FeatureEndDate == null))
.ToList<FeaturedTrack>();
My table is currently empty, now I know this table won't be empty but it got me wondering about how to handle the NullReference error in case it is.
I've tried this:
int test = _db.FeaturedTracks.Count();
if (test > 0)
{
...
}
However my code breaks on the first line, so how do I check the table is empty before running the statement?

Related

Add a Contains("string") functionality Azure Table LINQpad query?

OK, this doesn't work due to Azure Table query subset constraints:
var res = tcmarketnlog.Where(t => t.Level == level && t.Message.Contains("151207151510") && t.Timestamp >= start && t.Timestamp <= end).Take(1000);
The t.Message.Contains("151207151510") bombs. However, there must be some way to then search the results in LINQpad and select only the results with this string in the message.
For example, I could not coerce the result into a variable that was then queriable again with LINQ. Any tips?
If you can't use string.Contains on an Azure Table Queryable, you can still turn it into an Enumerable and then apply the additional filter to only show the results you want. However, it means that it will return all records that meet the other criteria over the network before then limiting them on the client side to only those rows where the Message field contains the specified string.
var res = tcmarketnlog.Where(t => t.Level == level && t.Timestamp >= start && t.Timestamp <= end).AsEnumerable().Where(t => t.Message.Contains("151207151510")).Take(1000);
Maybe message is null. Just check message null before contains. pls try this:
var res = tcmarketnlog.Where(t => t.Level == level
&& t.Message != null && t.Message.Contains("151207151510")
&& t.Timestamp >= start && t.Timestamp <= end).Take(1000);

How to pass an external parameter to LINQ where clause in CRM

I have a LINQ query which works fine as for stand alone lists but fails for CRM
var lst = new List<bool?>();
lst.Add(null);
lst.Add(true);
lst.Add(false);
bool IsWet = false;
var newlst = from exch_HideVoiceSignature in lst where
(((exch_HideVoiceSignature!=null && exch_HideVoiceSignature==false
|| exch_HideVoiceSignature== null) )&& !IsWet) select exch_HideVoiceSignature;
newlst.Dump();
var question = from q in exch_questionSet where ((q.exch_HideVoiceSignature != null
&& q.exch_HideVoiceSignature.Value == 0 )|| q.exch_HideVoiceSignature == null )
&& !IsWet select q.exch_HideVoiceSignature;
question.FirstOrDefault().Dump();
As you can see I can pass the variable IsWet to LINQ query for a standard list fine and get values for first list. But when I execute the same for second list, I get the following error
Invalid 'where' condition. An entity member is invoking an invalid property or method
The CRM LINQ provider won't support the evaluation you attempting. It only supports evaluation of where criteria is evaluating an entity field.
That's not a problem. Since you want the LINQ query to only use the where clause if IsWet is false (correct me if I'm wrong on that.) So we simply do the evaluation to determine if the where clause should be added or not. Then execute your query.
var question = from q in exch_questionSet
select q.exch_HideVoiceSignature;
if (!IsWet)
{
question.Where(x => ((x.exch_HideVoiceSignature != null
&& x.exch_HideVoiceSignature.Value == 0) || x.exch_HideVoiceSignature == null));
}
question.FirstOrDefault().Dump();
I am constantly confronted with that problem.
Try to "detach" (for example call .ToArray()) your query (while it is "clear") from CRM and then filter query using external parameter. This should help.
var question =
(from q in exch_questionSet
where (
(q.exch_HideVoiceSignature != null && q.exch_HideVoiceSignature.Value == 0 ) ||
q.exch_HideVoiceSignature == null )
select q.exch_HideVoiceSignature
).ToArray().Where(q => !IsWet);
question.FirstOrDefault().Dump();
UPDATE
If you are using IsWet flag to control blocks of conditions (enable and disable them from the one point in the code) then probably you may be interested in class named PredicateBuilder which allows you to dynamically construct predicates.
Just because I had an existing query with lot of other joins etc. and I wanted to pass this additional parameter to it I ended up using a var statement which dumps the rows to a list and applies the where clause in the same statement
bool IsWet =true ;
var question = ...existing query ...
select new {
...existing output ...,
Wet =q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080001,
Voice = q.exch_HideVoiceSignature == null ||
(q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080000) ,
}
;
var qq = IsWet ?
question.ToList().Where(X=> X.Wet ) :
question.ToList().Where(X=> X.Voice );
qq.FirstOrDefault().Dump();

Why is LINQ query to DataTable not working?

I have a DataTable, dt, that contains the following:
As you can see, there are two sets of files here: baseline (columns 1-3) and target (columns 4-6). So in this case I have 4 baseline files, m4, m5, m1, and m3 (m1 in row 5 is copied from row 3) and one target file, m1. The problem is that the information for the baseline file m1.txt is duplicated, so I'm trying to remove it using the following LINQ statement:
var extraneousRows = dt.Rows.Cast<DataRow>().
Where(
row => row["BASELINE_FOLDER"] == baselineSubfolder
&& row["BASELINE_FILE"] == baselineFilename
&& row["BASELINE_CHECKSUM"] == baselineChecksum
&& row["STATUS"] == "remove"
).ToArray();
foreach (DataRow dr in extraneousRows)
{
dt.Rows.Remove(dr);
}
This should remove the 3rd row from the DataTable but it doesn't. The code works fine if I omit the && row["STATUS"] == "remove" line, so I know it's functional. And the values for baselineSubfolder, baselineFilename, and baselineChecksum are correct, so that's not the problem.
But for some reason, when I include that line about the status column, it doesn't detect that that row is in the DataTable, even though it clearly is according to the DataSet Visualizer (photo above). So it's never entering the foreach loop and not removing the necessary files. Why???
I maybe should mention that the baseline file information (first 4 rows) are being retrieved from a database, whereas the target file fields are being generated according to user input. I don't see how it would matter where the information is coming from, though, since I'm querying the DataTable directly...
UPDATE
Ok, after following the suggestions of idipous and Jamie Keeling, I've determined that the problem had to do with the foreach loop, which was never being populated. Since this query should only ever return a single row, I eliminated the loop altogether. My revised code looks like this:
var extraneousRows = dt.Rows.Cast<DataRow>().
Where(
row => row["BASELINE_FOLDER"] == baselineSubfolder
&& row["BASELINE_FILE"] == baselineFilename
&& row["BASELINE_CHECKSUM"] == baselineChecksum
&& row["STATUS"] == "remove"
).SingleOrDefault();
dt.Rows.Remove(extraneousRows);
For whatever reason, extraneousRows remains null and that last line is generating a runtime error: IndexOutOfRangeException: The given DataRow is not in the current DataRowCollection
Why isn't this working?
It actually turns out that the problem was that I needed to cast the column values to strings. The solution was incredibly simple: just add a .ToString() after the column names and viola! The following code worked like a charm:
var extraneousRows = dt.Rows.Cast<DataRow>().
Where(
row => row["BASELINE_FOLDER"].ToString() == baselineSubfolder
&& row["BASELINE_FILE"].ToString() == baselineFilename
&& row["BASELINE_CHECKSUM"].ToString() == baselineChecksum
&& row["STATUS"].ToString() == "remove"
).SingleOrDefault();
dt.Rows.Remove(extraneousRows);
I also found a non-LINQ way to do this, by iterating through all the rows of the DataTable. It's not the most efficient, but it works:
for (int z = 0; z < dt.Rows.Count; z++)
{
if ((dt.Rows[z]["BASELINE_FOLDER"].ToString() == baselineSubfolder)
&& (dt.Rows[z]["BASELINE_FILE"].ToString() == baselineFilename)
&& (dt.Rows[z]["BASELINE_CHECKSUM"].ToString() == baselineChecksum)
&& (dt.Rows[z]["STATUS"].ToString() == "remove"))
{
dt.Rows[z].Delete();
}
}
dt.AcceptChanges();

LINQ query does not "see" the values in array

here is my query
var traj_of_user_2=
from num in trajectoryArray
where num.ID_User == 2
select num.ID_Traj;
when i run the program, an exception appears (see the image)
what's the problem is your opinion? a friend of me told me that since the array is "lazy" there are no istances
There is a null in the array, and num.ID_User is failing. You can filter out nulls like this:
var traj_of_user_2=
from num in trajectoryArray
where num != null &&
num.ID_User == 2
select num.ID_Traj;
Only get ID_User when num != null
var traj_of_user_2=
from num in trajectoryArray
where (num != null && num.ID_User == 2)
select num.ID_Traj;

Linq Subquery Where Clause

I need some help with thsi linq query. It shoudl be fairly simple, but it is kicking my butt.
I need to use a subquery to filter out data from the main query, but every path I have tried to use results in failure.
The subquery by itself looks like this.
int pk = (from c in context.PtApprovedCertifications
where c.FkosParticipant == 112118 &&
(!excludedActionTypes.Contains(c.FkMLSosCodeActionType)) &&
c.EffectiveDate <= DateTime.Now &&
c.FkptApprovedCertificationVoidedBy == null
orderby c.EffectiveDate descending,c.PK descending
select c.PK).FirstOrDefault();
This works as expected but as you can see I plugged in the number 112118. This should be the primary key from main query.
The combined query I've been working on looks like this.
IQueryable<PtAMember> result = (from p in context.PtAMembers
where (p.FkptACertification == (from c in context.PtApprovedCertifications
where c.FkosParticipant == p.PtApprovedCertification.OsParticipant.PK &&
(!excludedActionTypes.Contains(c.FkMLSosCodeActionType)) &&
c.EffectiveDate <= DateTime.Now &&
c.FkptApprovedCertificationVoidedBy == null
orderby c.EffectiveDate descending, c.PK descending
select c.PK).FirstOrDefault()) &&
(p.LastName.ToLower().Contains(param.ToLower()) ||
p.FirstName.ToLower().Contains(param.ToLower()) ||
p.SocialSecurityNumber.Contains(param))
select p).Distinct().OrderBy(PtAMembers => PtAMembers.LastName).ThenBy(PtAMember => PtAMember.FirstName);
This results in an error though. Any help in solving this conundrum would greatly appreciated.
Thanks!
How about turning your subquery into a lookup function:
Func<int, int> pkLookup = n => (from c in context.PtApprovedCertifications
where c.FkosParticipant == n &&
(!excludedActionTypes.Contains(c.FkMLSosCodeActionType)) &&
c.EffectiveDate <= DateTime.Now &&
c.FkptApprovedCertificationVoidedBy == null
orderby c.EffectiveDate descending,c.PK descending
select c.PK).FirstOrDefault();
then using that in your main query.

Resources