Matas Vaitkevicius
Matas Vaitkevicius

Reputation: 61519

DefaultIfEmpty returning null

I am working with C#, .NET4.5, EF6(shouldn't matter really).

I am selecting some values from db then .ToList() them and then adding DefaultIfEmpty(new ActualFee{Net = 0, Vat = 0}) if one does not exist, and I get null

public static ConveyancingSummaryVm ToConveyancingSummaryVm(this Tuple<IEnumerable<ActualFee>, ConveyancingAnswer, Customer> conveyancePricingAnswersAndCustomer)
        {
            var purchaseFees = conveyancePricingAnswersAndCustomer.Item1.Where(o => o.ConveyancingSaleType == "Purchase").ToList();

            if (purchaseFees.Any())
            {
                var discount = purchaseFees.DefaultIfEmpty(new ActualFee{Net = 0, Vat = 0}).SingleOrDefault(o => o.Title.Contains("Discount")); 

                conveyancingSummaryVm.IsPurchaseFreehold = conveyancePricingAnswersAndCustomer.Item2.PropertyBoughtIsFreehold;
...

enter image description here

I must be missing something obvious here.

Upvotes: 3

Views: 7217

Answers (3)

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101731

There is no way for DefaultIfEmpty to return null in this case. When there is no element it returns an ActualFee instance and the Title does not contain Discount. So that's why SingleOrDefault returns null.

so you are saying that DefaultIfEmpty does not work for SingleOrDefault?

No, DefaultIfEmpty works and returns the expected value. And then SingleOrDefault runs on the return value of DefaultIfEmpty and returns null because there is no element in the sequence that satisfies your condition.

You can use null coalescing operator to get the behaviour you want:

var discount = purchaseFees.FirstOrDefault(o => o.Title.Contains("Discount")) 
              ?? new ActualFee{Net = 0, Vat = 0};

Upvotes: 5

Matas Vaitkevicius
Matas Vaitkevicius

Reputation: 61519

OP here: Figured another workaround.

Rather than using Single() if you are willing to 'sacrifice' the check for it to be single record what you can do is use Where() and Sum() combo.

I know there's always one or zero Severances.

Example:

var feeValue = legalFees.Where(o => o.Title.Contains("Severance"));
premiumDetails.LegalFeeNet = feeValue.Sum(o => o.Net);
premiumDetails.LegalFeeVat = feeValue.Sum(o => o.Vat);

if there are no records this returns 0 for Net and Vat and if there is - returns the values.

UPDATE - Figured another one:

legalFees.Where(o => o.Title.Contains("Severance")).Union(new ActualFee{Net = 0, Vat = 0}).First();

if Where() does return something then First() will be the value that Contains("Severance"), if it does not - then First() will be whatever is in Union().

Upvotes: 0

JunaidKirkire
JunaidKirkire

Reputation: 918

SingleOrDefault must've returned null. If DefaultIfEmpty had returned null, it would've returned a Object reference not set to an instance of an object. Please rewrite that statement without chaining.

Upvotes: 2

Related Questions