I have a lambda expression that I want to shorten by combining two function calls inside. If you see in below code I am calling this.adgroupRepository.GetBidRange twice. There has to be a way to combine these calls into one and just pass the FloorValue and CeilingValue from within.
Can someone help?
new JsonResult
{
Data = result.Data.Where(x => x.Bidding != null).Select(
x => new
{
x.ID,
x.Name,
BidRange = new
{
FloorValue = (x.Bidding.FloorPrice != null) ? x.Bidding.FloorPrice : this.adgroupRepository.GetBidRange(this.contextProvider.CurrentAccount.CurrencyCode, x.PricingModel, x.Bidding.Type).FloorValue,
CeilingValue = (x.Bidding.CeilingPrice != null) ? x.Bidding.CeilingPrice : this.adgroupRepository.GetBidRange(this.contextProvider.CurrentAccount.CurrencyCode, x.PricingModel, x.Bidding.Type).CeilingValue
},
DefaultBid = x.Bidding.BroadBid
})
};
You can always use a lambda statement instead of an expression. That allows you to write a block of code, create local variables, and then return the result. Also you can use the null-coalescing operator ?? instead of the conditional operator with a null check.
new JsonResult
{
Data = result.Data.Where(x => x.Bidding != null).Select(
x =>
{
var bidRange =
x.Bidding.FloorPrice == null
|| x.Bidding.CeilingPrice == null ?
this.adgroupRepository.GetBidRange(
this.contextProvider.CurrentAccount.CurrencyCode,
x.PricingModel,
x.Bidding.Type) :
null;
return new
{
x.ID,
x.Name,
BidRange = new
{
FloorValue = x.Bidding.FloorPrice ?? bidRange.FloorValue,
CeilingValue = x.Bidding.CeilingPrice ?? bidRange.CeilingValue
},
DefaultBid = x.Bidding.BroadBid
};
})
};
Something like this?
new JsonResult
{
Data = result.Data.Where(x => x.Bidding != null).Select(x =>
{
var bidRange = adgroupRepository.GetBidRange(
contextProvider.CurrentAccount.CurrencyCode,
x.PricingModel,
x.Bidding.Type);
return new
{
ID = x.ID,
Name = x.Name,
BidRange = new
{
FloorValue = x.Bidding.FloorPrice ?? bidRange.FloorValue,
CeilingValue = x.Bidding.CeilingPrice ?? bidRange .CeilingValue
},
DefaultBid = x.Bidding.BroadBid
}
})
};
Related
I want to change this code from entity to linq.
I always get the error "value cannot be null. parameter name: text"
how to fix that error
public ActionResult Search(SearchView search)
{
IEnumerable<Transaction> thunhaps = null, chitieus = null;
decimal totalTN = 0, totalCT = 0;
int userid = Convert.ToInt32(Session["userid"]);
//var trans = new List<Transaction>();
QuanLyChiTieuDataContext context = new QuanLyChiTieuDataContext();
List<Transaction> trans = new List<Transaction>();
if (search.MoTa != null)
search.MoTa = "";
if (search.TransType == "i" || search.TransType == "b")
{
thunhaps = from item in context.ThuNhaps
where item.UserID == userid
&& item.MoTa.Contains(search.MoTa)
&& item.Ngay.Value >= search.TuNgay &&
item.Ngay <= search.DenNgay
select new Transaction
{
Id = item.Inc_Id,
SoTien = (decimal)item.SoTien,
MoTa = item.MoTa,
GhiChu = item.GhiChu,
NgayGD = item.Ngay.Value,
TransType = "Income"
};
totalTN = thunhaps.Sum(t => t.SoTien);
//List<ThuNhap> thuNhaps = new List<ThuNhap>();
//var totalTNhap = thuNhaps.Sum(t => t.SoTien);
}
if (thunhaps != null)
trans.AddRange(thunhaps);
ViewBag.Difference = totalTN - totalCT;
return PartialView("SearchResult", trans);
}
I very hard to try the change but I failed`
When asking questions in StackOverflow you should be clearer.
A working sample would make a lot easier for anyone to help you.
That being said, you probably get the error because you are querying a recent created context object (and context.ThuNhaps is probably empty, and item.MoTa is null and item.Ngay is null, ...).
Now, I don't know if your question is about the error or "change the entity to linq", which I think you meant change the syntax of LINQ being used, from Query (Comprehension) Syntax to Lamda (Method) Syntax.
Something like:
thunhaps = context.ThuNhaps
.Where(item =>
item.UserID == userid
&& item.MoTa.Contains(search.MoTa)
&& item.Ngay.Value >= search.TuNgay
&& item.Ngay <= search.DenNgay)
.Select(item =>
new Transaction
{
Id = item.Inc_Id,
SoTien = (decimal)item.SoTien,
MoTa = item.MoTa,
GhiChu = item.GhiChu,
NgayGD = item.Ngay.Value,
TransType = "Income"
});
What I'm doing wrong in this method below? I created a group with linq because I need to group the list by 2 columns and for this grouping I will have a list of files.
[HttpGet]
[Route("versions-by-period")]
public IActionResult GetVersionsByPeriodId(int entityId, int periodId)
{
var versionsInvoiceBillet = db.RemittanceInvoiceBilletVersionsCompacts
.Where(x => x.LegalEntityId == entityId && x.PeriodId == periodId && x.IsCurrent && x.DownloadHash != null)
.GroupBy(x => new { x.LifePolicyNumber, x.LegalEntityGroupNumber },
i => new { i.DownloadHash, i.FileTypeEnum, i.DueDate }, (key, group) => new
{
LifePolicyNumber = key.LifePolicyNumber,
LegalEntityGroupNumber = key.LegalEntityGroupNumber,
Files = group.ToList()
});
return Ok(versionsInvoiceBillet.Select(x => new {
lifePolicyNumber = x.LifePolicyNumber,
legalEntityGroupNumber = x.LegalEntityGroupNumber,
invoiceAndBillet = x.Files.Select(f => new {
downloadHash = f.DownloadHash,
fileTypeEnum = f.FileTypeEnum,
dueDatet = f.DueDate
})
}));
}
If I try to call this method with Postman, the body comes empty. The problem is in invoiceAndBillet information that is returned, if I change to below, the body comes filled.
return Ok(versionsInvoiceBillet.Select(x => new {
lifePolicyNumber = x.LifePolicyNumber,
legalEntityGroupNumber = x.LegalEntityGroupNumber,
invoiceAndBillet = x.Files.Select
}));
If I try to debug the selection that I'm trying to return, I get this message below:
We are having a hard time trying to figure out the best way to handle this with out declaring a loop after you get the data.
For instance take this piece of code: (Data2 is tied to Data with a foreign key)
context.Data.Select(_ => new DataModel
{
Id = _.Id,
Data2 = new Data2Model
{
Id = _.Data2.Id,
Name = _.Data2.Name,
Date = _.Data2.Date
},
Date = _.Date
});
If _.Data2 is not null then this runs correctly but if _.Data2 happens to be null then this will error. The way we are getting around this now is to add Data2Id to our DataModel and then loop through all of the records to get the information if its not null.
var lst = context.Data.Select(_ => new DataModel
{
Id = _.Id,
Data2Id = _.Data2ID
Date = _.Date
}).ToList();
foreach(var item in lst)
{
if (item.Data2Id != null)
{
var dataItem = context.Data2.FirstOrDefault(_ => _.Id == item.Data2Id);
item.Data2 = new Data2Model
{
Id = dataItem.Id,
Name = dataItem.Name,
Date = dataItem.Date
}
}
}
Is there a cleaner / better way to keep this in the original select loop.
Thanks
Try:
Data2 = _.Data2 == null ? null : new Data2Model
{
Id = _.Data2.Id,
Name = _.Data2.Name,
Date = _.Data2.Date
},
context.Data.Select(_ => new DataModel
{
Id = _.Id,
Data2 = _.Data2 == null ?
new Data2Model{Id = _.Data2ID} :
new Data2Model{ Id=_.Data2.Id, Name=_.Data2.Name, Data=_.Data2.Date},
Date = _.Date
});
I'm making the assumption that if it is null you still have the _.Data2ID at hand?
Using the ternary operator
If Data2 is null then return a new Data2Model with just the other _.Data2ID value
If it is not null then go ahead and create a new Data2Model with all the details.
You can extract the logic in separate method to shorten your LINQ query and potentially reuse your code:
private static DataModel Map(DataModel _)
{
Data2Model model = _.Data2 ?? new Data2Model();
return new DataModel
{
Id = _.Id,
Date = _.Date,
Data2 = new Data2Model
{
Id = model.Id,
Name = model.Name,
Date = model.Date
}
};
}
Your query than becomes:
context.Data.Select(Map);
You should replace the artificial types with your own.
var items = pSelectedItem.Nodes
.Expand(e => e.Nodes)
.Where(e => e.Nodes == null)
.Select(e => e.Tag as List<ActionObject>)
.Select(e=> e.Select (i=>i as ActionObject)
.Where(i => i != null)
.Select(i => new ListViewItem()
{
Tag = new ListViewValue[]
{
new ListViewValue() { Value = i.Command },
new ListViewValue() { Value = i.Target },
new ListViewValue() { Value = i.Value },
new ListViewValue() { Value = i.Comment }
}
}) as ListViewItem);
return new ObservableCollection<ListViewItem>(items);
The code above, I am trying to capture all listviewitems. Each list view item has a tag property. This tag property is of type object.
The code above makes complete sense to me however its always returning null. I have tried debugging the code above unfortunately the code above doesn't let me debug the inner select code. the e.Select (i=>.... is where it won't debug.
Thoughts? Maybe my code is more complicated than it needs to be.
Try SelectMany instead, you're currently selecting a IEnumerable<IEnumerable<ListViewItem>>:
var items = pSelectedItem.Nodes
.Expand(e => e.Nodes)
.Where(e => e.Nodes == null && e.Tag is List<ActionObject>)
.Select(e => (List<ActionObject>)e.Tag)
.SelectMany(aclist => aclist.Where(ac => ac != null))
.Select(i => new ListViewItem()
{
Tag = new ListViewValue[]
{
new ListViewValue() { Value = i.Command },
new ListViewValue() { Value = i.Target },
new ListViewValue() { Value = i.Value },
new ListViewValue() { Value = i.Comment }
}
};
one way to debug is start commenting out Where statements one by one and see if you get results. this will help you in understanding which where clause is causing your results to come back as null. you can go from there.
I am trying get data from the xml. Below is the code which
gets data from the XDocument and return list<t>.
However, p.Element("Sponsor") can sometimes be null. How can I check for the null values
var atClauseList = doc.Descendants(CLAUSE_GROUP_TAG).Descendants(AT_CLAUSE_TAG).Select(p => new AtClause()
{
ClauseNumber = (string)p.Element("Number"),
Sponsors = p.Element("Sponsor").Elements(SPONSOR_TAG).Select(y => y.Value)
.ToList(),
Page = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Page").ElementValueNull(),
Line = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Line").ElementValueNull(),
LineText = p.Element("Sponsor").Element("aItem").Element("AmendText").Nodes().OfType<XText>().FirstOrDefault().XTextValueNull(),
ItalicText = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Italic").ElementValueNull(),
ParaList = p.Element("Sponsor").Element("aItem").Element("AmendText").Elements("Para").Select(L => new Para
{
ParaText = (string)L,
Number = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Number"),
Quote = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Quote"),
}
).ToList()
}).ToList();
move your code out of an object initializer, and add some logic to it:
var atClauseList = new List<AtClause>();
foreach(var item in doc.Descendants(CLAUSE_GROUP_TAG).Descendants(AT_CLAUSE_TAG))
{
var atClause = new AtClause();
atClause.ClauseNumber = (string)item.Element("Number");
var sponsor = item.Element("Sponsor");
if (sponsor != null)
{
atClause.Sponsors = sponsor.Elements(SPONSOR_TAG).Select(y => y.Value).ToList();
atClause.Page = sponsor.Element("aItem").Element("AmendText").Element("Page").ElementValueNull();
atClause.Line = sponsor.Element("aItem").Element("AmendText").Element("Line").ElementValueNull();
atClause.LineText = sponsor.Element("aItem").Element("AmendText").Nodes().OfType<XText>().FirstOrDefault().XTextValueNull();
atClause.ItalicText = sponsor.Element("aItem").Element("AmendText").Element("Italic").ElementValueNull();
atClause.ParaList = sponsor.Element("aItem").Element("AmendText").Elements("Para").Select(L => new Para
{
ParaText = (string)L,
Number = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Number"),
Quote = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Quote"),
}).ToList();
atClauseList.Add(atClause);
}
You can use sequences rather than leaving the IEnumerable immediately:
var value = (string)p.Elements("Sponsor")
.Elements("aItem")
.Elements("AmendText")
.Elements("Page")
.SingleOrDefault()