Best practice of SingleOrDefault() - c#

I want to make my code better. Can I safely rewrite the first example to the second?
IQueryable<PDF> pdfList = (from pdfobj in pdfDataContext.PDFs
where pdfobj.Id == pdfId
select pdfobj);
if (pdfList.Count() > 0)
{
PDF pdfOldWay = pdfList.FirstOrDefault();
pdfOldWay. // do something. (pdfOldWay can't be null here...)
}
--
PDF pdfNewWay = (from pdfobj in pdfDataContext.PDFs
where pdfobj.Id == pdfId
select pdfobj).SingleOrDefault();
if (pdfNewWay != null)
{
// do something
}
--
EDIT:
Sorry for not being clear. My issue is to get the PDF object out directly without having to use a list first. I don't want to make a check for count is greater than 0 and because it just doesn't look good.

Yes, that looks safe. You can also simplify your query slightly:
PDF pdfNewWay = pdfDataContext.PDFs.SingleOrDefault(p => p.Id == pdfId);
if (pdfNewWay != null)
{
// do something
}
The only difference between SingleOrDefault and FirstOrDefault is that SingleOrDefault will throw an exception if more than one match is found, so unless you want this check then you may as well stick to FirstOrDefault.

You should use FirstOrDefault in the second case too as SingleOrDefault will throw an exception if there is more than one item. Is that ok for you?
On the other hand if you want to guarantee that there is only one pdfobject for some id than using SignleOrDefault is better.

If it's guaranteed that it always has 0 or 1 rows, then sure, SingleOrDefault is the best solution.

Yes you will achieve the same result, I don't see any issue.

Related

DataTable Linq with two join statements in C#

My code:
var Result = from TempRow in ArrAbsDiff
where TempRow.Strike == StrikeOfMinAbsDiff
select TempRow.PutMidPrice;
I know that the above code return just one value of type decimal (maybe double). However, Result is of type Enumerable and I could not easily write Result + 2. I need to convert it property. I can do it through the following code:
var Result = (from TempRow in ArrAbsDiff
where TempRow.Strike == StrikeOfMinAbsDiff
select TempRow.PutMidPrice).Min();
Is there more efficient way to accomplish it?
Regards,
I know that the above code return just one value of type decimal
Then use First method instaed of Min.
At compile time, it's unknown whether the query you have returns 1 record or more than 1 record. So, it assumes a list of them.
I don't know if there is a performance difference between them, I typically use .Single() to get the single record. It's more clear that I want a single record and not, for example, the minimum one.
Try using FirstOrDefault()" this selects the first result returned (as you know only one value will be returned). if a value is not returned the Result will be null, catch this in an if statement like below:
var Result = (from TempRow in ArrAbsDiff
where TempRow.Strike == StrikeOfMinAbsDiff
select TempRow.PutMidPrice).FirstOrDefault();
if (Result == null)
return; // or error message
this will also keep the type of value returned
(typed this of the top of my head, may need slight changes!)

Do Loop, an efficient break method?

I have a section inside a method that does something similar too:
do
{
// some query
// another query
if another query != null
{
// return something
}
}while(some query != null)
Obviously this does not work, because some query is not declared until it is inside the loop. One solution I tried was
bool flag = false;
do
{
// some query
if some query == null
{
flag = true;
// or
break;
}
// another query
if another query != null
{
// return something
}
}while(flag != true)
Neither method really satisfies me, and quite honestly I am not sure if they would be considered good coding practice, which irks me. Moreover this has pretty much has been my go to solution in cases like this up until this point, but due to the garbage nature of the flag, I wanted to find out if there is a better way to handle this for future reference, instead of making a junk variable. I should note the other solution which I thought of would arguably be uglier. That solution being to run the query once outside the loop, and convert it into a while loop and recall the query again inside itself, rather than a do loop.
While the code works with the above solution, I was wondering if anyone had a better solution that does not require an arguably pointless variable.
Though I understand that such a better solution may not be possible, or really even needed, it could be ridiculous to even try.
Having a break or flag variable isn't what would make something inefficient, it's what inside the loop that should be your concern. In other words it's just a preference and either is fine.
I think you need
while(true)
{
// some query
if some query == null
{
break;
}
// another query
if another query != null
{
// return something
}}
You can try this:
do
{
// some query
if some query == null
{
break;
}
// another query
if another query != null
{
// return something
}
}while(true);

Dataset comparison with Null Value c#

Goodday
I can't seem to use my dataset in a Null comparison
I'm trying to make an statement (attempts go below) where it will only continue my code when my dataset is empty.
Code 1:
if ((string)dts.Tables[0].Rows[0]["RECID"] != null)
^ just skips my if, I know that it's empty (checked my watch), still continues even when it is null.
Code 2:
long Recid = 0;
Boolean checkrecid = long.TryParse((string)dts.Tables[0].Rows[0]["RECID"], out Recid);
if (checkrecid == false)
^ Crashes at my Tryparse. I know you can use Trycatching, but I don't want to use it, cause it will make my program run slower, and it needs to read a good 10000 lines a day ...
Error:
A first chance exception of type 'System.IndexOutOfRangeException' occurred in System.Data.dll
Meaning that it can't find anything, but I know that already.
EDIT: I do not want an error. Any previous methods, who all work in other cases, return an indexoutofrange error. I'll add this ..
The dataset is filled with data from an SQL server based on phonenumbers and other data.
If he can't find the phonenumber, which comes from a text file, he will return nothing, no row, no column, nothing.
Thanks in advance,
DZ
You need to use DBNull.Value instead of null
EDIT: Index outside the bounds may mean there are no rows at all. Try replacing your if with this:
if (dts.Tables[0].Rows.Count > 0 && dts.Tables[0].Rows[0]["RECID"] != DBNull.Value)
{
}
This line:
if ((string)dts.Tables[0].Rows[0]["RECID"] != null)
needs to be
if ((string)dts.Tables[0].Rows[0]["RECID"] != DBNull.Value)
Or you could delete that check:
Boolean checkrecid = long.TryParse((dts.Tables[0].Rows[0]["RECID"] ?? string.Empty), out Recid);
if((string)dts.Tables[0].Rows[0]["RECID"] is DBNull)
{ // will go here }
Found it!
int strTables = dts.Tables[0].Rows.Count;
if (strTables == 1){ //code goes here}
A type-safe alternative is using Field extension method. It will return 'null' instead of DBNull.Value for empty fields.
if (dts.Tables[0].Rows[0].Field<string>("RECID") != null)

C# Elegant way to handle checking for an item in a collection

I've posted a code sample below. Firstly let me explain
termStore.Groups in the code below is a collection of Group Objects (The exact class is irrelevant).
Checking for null : if (termStore.Groups[groupName] == null) seems like a logical (clean) approach, but if the Groups collection is empty then an exception is produced.
using the termStore.Groups.Contains is not an option either because this expects a strong type i.e: .Contains(Group)... not .Contains(GroupName as string)
Can someone recommend a clean / generic way I can check for if an item exists in collection .
Thank you....
TermStore termStore = session.TermStores.Where(ts => ts.Name == termStoreName).FirstOrDefault();
if (termStore.Groups[groupName] == null)
{
termStore.CreateGroup(groupName);
termStore.CommitAll();
}
Update: The exact class Sharepoint Taxonomy Classes. http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.taxonomy.group.aspx
Update 2, the exact collection : http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.taxonomy.groupcollection.aspx
Microsoft.SharePoint.Taxonomy.GroupCollection implements IEnumerable<Group>, so a bit of LINQ is probably just what the doctor ordered:-
if(termStore.Groups.Any(x => x.Name == "MyGroup"))
{
// group contains at least one item matching the predicate.
}
else
{
// group contains no items matching the predicate.
}
You'll need to be using .NET 3.5 or better and add "using System.Linq;" to the top of your file.
Edit
If you don't have LINQ available, or if it offends you, or if you've genuinely profiled and found that iterating over Groups is killing performance compared to the string indexer, you could use GroupCollection.Count to avoid the error state:-
if (termStore.Groups.Count == 0 || termStore.Groups[groupName] == null)
{
// Group doesn't exist.
}
IEnumerable.Any(...) should work for your case:
termsStore.Groups.Any()
I think this is what you are looking for:
termStore.Groups.ContainsKey(groupName)
Checks that the key exists, doesn't throw an exception if it doesn't. This is assuming that Groups is a collection that implements IDictionary.
May be this
termStore.Any() && termStore.Groups.Any() && termStore.Groups[groupName] == null
Ok, 2nd attempt. If Groups doesn't contain the required ContainsKey method then you can write it yourself. Then you can just use ContainsKey in place of Contains.
static class GroupExtensions
{
public static bool ContainsKey(this Groups groups, string key)
{
try
{
if(groups[key] == null)
{
return false;
}
}
catch
{
return false;
}
return true;
}
}

Need help with a LINQ ArgumentOutOfRangeException in C#

Hoping this is a nice softball of a question for a friday but I have the following line of code:
//System.ArgumentOutOfRangeException generated if there is no matching data
currentAnswers = new CurrentAnswersCollection()
.Where("PARTICIPANT_ID", 10000).Load()[0];
CurrentAnswersCollection is a strongly-typed collection populated by a view going back to my database.
The problem of course is that if there is not a corresponding PARTICIPANT_ID = 10000 I get the error message.
Is there a better way to write this so that I wouldn't get the error message at all?
I just dont know enough about LINQ syntax to know if I can test for the existance first?
thanks.
Use this:
currentAnswers = new CurrentAnswersCollection()
.Where("PARTICIPANT_ID", 10000).Load()
.FirstOrDefault();
It'll return null if there is no first element.
But you may need to fix your code (replicated here) first - the .Where syntax looks dodgy.
The ArgumentOutOfRangeException is occurring when you try to use the indexer to get the first item from the (empty) list. Using the FirstOrDefault() extension method is a convenient way to return the first element of a collection, if there is one, otherwise to return null.
currentAnswers = new CurrentAnswersCollection().Where("PARTICIPANT_ID", 10000)
.Load()
.FirstOrDefault();
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.firstordefault.aspx
Try:
var answers = new CurrenAnswersCollection().Where("PARTICIPANT_ID", 10000);
if(answers.Count() >= 1) currentAnswers = answers.Load()[0];
or something similar.
You need a lambda expression in .Where.
currentAnswers = new CurrentAnswersCollection()
.Where(c => c.PARTICIPANT_ID == 10000).Load().FirstOrDefault();

Categories

Resources