简体   繁体   中英

Avoiding null exception in EF that is thrown by your query

I have a query like this :

        result =
            firstIdeaRepository.FindBy(
                i => i.FirstIdeaState == FirstIdeaState && i.Date >= start && i.Date <= end)
                               .AsEnumerable()
                               .Select(j => new RptListOfCompanyBasedOnFirstIdeaState()
                                   {
                                       Name =
                                           companyRepository.FindBy(i => i.UserId == j.UserId)
                                                            .FirstOrDefault()
                                       DateOfMeeting =
                                           calenderRepository.ConvertToPersianToShow(
                                               meetingReposiotry.FindBy(s => s.FirstIdeaId == j.Id)
                                                                .FirstOrDefault()
                                                                .Date),
                                       DateOfExit =
                                           calenderRepository.ConvertToPersianToShow(j.DateOfExit.Value),
                                       ReasonOfExit = j.ReasonOfExit,
                                   }).ToList();

    return result;

As you can see i use FirstOrDefault() and j.DateOfExit.Value and sometimes my Date doesn't have any values or sometime my other variables are null too because i use firstordefaut() like

companyRepository.FindBy(i => i.UserId == j.UserId).FirstOrDefault().

So my query throws a null exception and the result can't be created ,how can i handle this exception and for example if the .NET detects the null value ignores it by default or uses a default values for that ?

Best regards.

Since you're using a nullable date, you can try filtering by values that have date, something like:

.FindBy(s => s.FirstIdeaId == j.Id && s.Date.HasValue)

This will ensure that you don't get any records with null date.

As I mentioned in comments, other cases need to be handled on case-by-case basis. Judging by the code you've shown, maybe you can handle Name as:

 Name = companyRepository.FindBy(i => i.UserId == j.UserId).FirstOrDefault() ?? "anonymous";

and so on.

Another example:

If you do want to get the record even if DateOfMeeting is null, then add a check for HasValue in subsequent part or default it to some date:

 DateOfExit = j.DateOfExit.HasValue ? 
              callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value)
              : (DateTime)null,   // you need to make `DateOfExit` nullable and then handle that downstream

// or (default with current date)
 DateOfExit = j.DateOfExit.HasValue ?
              callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value) 
              : callenderRepository.ConvertToPersianToShow(DateTime.Now),

// or (default with empty date)
 DateOfExit = j.DateOfExit.HasValue ?
              callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value) 
              : callenderRepository.ConvertToPersianToShow(new DateTime()),

Moral of the story: figure out what the default value should be in case of null and then substitute that accordingly in the query when calling FirstOrDefault() .

I would make the following changes:

result =
    firstIdeaRepository.FindBy(
        i => i.FirstIdeaState == FirstIdeaState && i.Date >= start && i.Date <= end)
            .AsEnumerable()
            .Select(j => new RptListOfCompanyBasedOnFirstIdeaState()
            {
                Name =
                    companyRepository.FindBy(i => i.UserId == j.UserId)
                        .FirstOrDefault()
                DateOfMeeting =
                    callenderRepository.ConvertToPersianToShow(
                        meetingReposiotry.FindBy(s => s.FirstIdeaId == j.Id)
                            // project a new sequence first, before calling `FirstOrDefault`:
                            .Select(s => s.Date)
                            .FirstOrDefault(),
                DateOfExit =
                    j.DateOfExit.HasValue ? 
                        callenderRepository.ConvertToPersianToShow(j.DateOfExit.Value) :
                        null,                       
                   ReasonOfExit = j.ReasonOfExit,
               }).ToList();

When you use FirstOrDefault , there's a possibility that you'll get null back (in the case of reference types), and so you need to plan for that in your code.

For example, when assigning DateOfMeeting , you could project the results (using .Select ) before using .FirstOrDefault , so that you're not ever accessing the Date property on what could be a null value.

As for DateOfExit , I've used the conditional operator to determine whether to call the calendarRepository 's method at all. This assumes that DateOfExit is nullable.

Unrelated : "Calendar" is spelled with one "l" and not two.

The broadest solution would be to use the idea of an null object with the DefaultIfEmpty<T>(T DefaultValue) method in your query. An example would be:

var defaultMeeting = new Meeting() { Date = new DateTime() };

var dateOfMeeting = meetingRepository.FindBy(s => s.FirstIdeaId == j.Id)
        .DefaultIfEmpty(defaultMeeting)
        .FirstOrDefault()
        .Date;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM