Refactor query in LINQ - c#

I have a query that needs to check the value from object list if it exists by loop through the value of the main object. How can recode below?
foreach (var kd in dto.KeyDriverModels)
{
var keyDriverModelNodeValue = result.SingleOrDefault(x => x.KeyDriverModelId == kd.ID);
kd.SelectionStatus = keyDriverModelNodeValue != null ?
keyDriverModelNodeValue.SelectionStatus : string.Empty;
}

I tried to model your code and rewrite the code as Linq. See if this works
static DTO dto = new DTO();
static void Main(string[] args)
{
List<KeyDriver> keyDrivers = new List<KeyDriver>();
List<KeyDriver> result = keyDrivers.Where(x => x.KeyDriverModelId > 1000).ToList();
foreach (var kd in dto.KeyDriverModels)
{
var keyDriverModelNodeValue = result.SingleOrDefault(x => x.KeyDriverModelId == kd.ID);
kd.SelectionStatus = keyDriverModelNodeValue != null ?
keyDriverModelNodeValue.SelectionStatus : string.Empty;
}
//new code
var kd1 = from r in result
join d in dto.KeyDriverModels
on r.KeyDriverModelId equals d.ID into drs
from dr in drs
select new { dr }.dr.SelectionStatus != null ? dr.SelectionStatus : string.Empty;
}
}
public class DTO
{
public List<KeyDriverModel> KeyDriverModels { get; set; }
}
public class KeyDriverModel
{
public int ID { get; set; }
public string SelectionStatus { get; set; }
}
public class KeyDriver
{
public int KeyDriverModelId { get; set; }
public string SelectionStatus { get; set; }
}
​

Related

Linq query for the Multi list in singe out put

i have table looks like below
ID | Reason | PrID
-----------------
1 abc null
2 dhe null
3 aerc 1
4 dwes 2
5 adfje 1
i have class
public class Reason
{
public int Id { get; set; }
public string Reson{ get; set; }
public List<SecondryReason> SecReason{ get; set; }
public int? PrimaryId { get; set; }
}
public class SecondryReason
{
public int Id { get; set; }
public string Reason { get; set; }
public int PrimaryReasonId { get; set; }
}
I want this to be displayed in hierarchy level
if the prid is Null need to treat this as the parent remaining all child
i am trying Linq and unable to achieve this
Suggest me how to do this in an easy way in linq
So: You have a list/enumerable of type , whereof the SecReason List property is null. Then, using linq you want a list, were the only the "root" reasons remain, but the Sub-reasons got put in the lists, but as type SecondaryReason?
If so, I found this way to do it (linq and foreach):
static IEnumerable<Reason> GetReasonsGrouped(List<Reason> reasons)
{
var result = reasons.Where(x => x.PrimaryId == null);
foreach (var item in result)
{
item.SecReason = reasons.Where(x => x.PrimaryId == item.Id)
.Select(x => new SecondryReason()
{ Id = x.Id,
ReasonName = x.ReasonName,
PrimaryReasonId = item.Id
})
.ToList();
}
return result;
}
Or just linq, but harder to read:
var result = reasons.Where(x => x.PrimaryId == null)
.Select(x =>
{
x.SecReason = reasons.Where(r => x.PrimaryId == x.Id)
.Select(r => new SecondryReason()
{
Id = r.Id,
ReasonName = x.ReasonName,
PrimaryReasonId = x.Id
})
.ToList();
return x;
});
Not sure if linq will be the best solution, here is my proposed changes and method to get an Hierarchy type:
public class Reason
{
public int Id { get; set; }
public string Reson { get; set; }
public List<Reason> SecReason { get; set; }
public int? PrimaryId { get; set; }
//Adds child to this reason object or any of its children/grandchildren/... identified by primaryId
public bool addChild(int primaryId, Reason newChildNode)
{
if (Id.Equals(primaryId))
{
addChild(newChildNode);
return true;
}
else
{
if (SecReason != null)
{
foreach (Reason child in SecReason)
{
if (child.addChild(primaryId, newChildNode))
return true;
}
}
}
return false;
}
public void addChild(Reason child)
{
if (SecReason == null) SecReason = new List<Reason>();
SecReason.Add(child);
}
}
private List<Reason> GetReasonsHierarchy(List<Reason> reasons)
{
List<Reason> reasonsHierarchy = new List<Reason>();
foreach (Reason r in reasons)
{
bool parentFound = false;
if (r.PrimaryId != null)
{
foreach (Reason parent in reasonsHierarchy)
{
parentFound = parent.addChild(r.PrimaryId.Value, r);
if (parentFound) break;
}
}
if (!parentFound) reasonsHierarchy.Add(r);
}
return reasonsHierarchy;
}

Convert double foreach to LinQ

foreach (var lg in basket)
{
foreach (var acc in lg.Accomodations)
{
if (acc.HotelID == h.ID)
{
hotel.SelectedInPreviousLeg = true;
}
}
}
I try to convert this double foreach to linq. Any suggestions?
So far i tried this, but there is a compile error.
var test = basket.FirstOrDefault(x => x.Accommodations, Any(y => y.HotelID == h.ID));
hotel.SelectedInPreviousLeg = (test != null) ? true : false;
or, assuming classes are defined equivalently to
public class Hotel
{
public int ID { get; set; }
public List<Accomodation> Accomodations { get; set; }
public bool SelectedInPreviousLeg { get set; }
}
public class Accomodation
{
public int HotelID { get; set; }
}
then you could do this:
foreach (var acc in
from lg in basket
from acc in lg.Accomodations
where acc.HotelID == h.ID
select acc)
hotel.SelectedInPreviousLeg = true;
... but that will iterate through all combinations, when you only need to find the first one that satisfies the condiditon, so you could do this, which will stop after finding the first one:
hotel.SelectedInPreviousLeg =
basket
.Any(b => b.Accomodations
.Any(a => a.HotelID == h.ID));

How to join tables only if not empty?

I have following LINQ query:
var LINQFilter = (from Cash in _DataTable_Cash.AsEnumerable()
join CashOpeningsAssignments in _DataTable_CashOpeningsAssignments.AsEnumerable().Where(a => (a.Field<Int32>("cashopeningassignmentstatus_id") == 1 || a.Field<Int32>("cashopeningassignmentstatus_id") == 2))
on Cash.Field<Int32>("cash_id") equals CashOpeningsAssignments.Field<Int32>("cash_id") into into_cashopeningsassignments
from CashOpeningsAssignments in into_cashopeningsassignments.DefaultIfEmpty()
join Users in _DataTable_Users.AsEnumerable()
on CashOpeningsAssignments.Field<Int32>("user_id") equals Users.Field<Int32>("user_id") into into_users
from Users in into_users.DefaultIfEmpty()
select new
{
cash_id = Cash.Field<Int32>("cash_id"),
cellar_name = Cellars.Field<String>("cellar_name"),
cash_name = Cash.Field<String>("cash_name"),
cashstatus_name = CashStatus.Field<String>("cashstatus_name"),
user_name = (Users == null ? "[No Data]" : Users.Field<String>("user_firstname") + (Char)32 + Users.Field<String>("user_lastname")),
cashtransaction_amount = (Cash.Field<Int32>("cashstatus_id") == 2 ? 0.00 : 150.00)
});
I have problems showing the result because this Field returns null: CashOpeningsAssignments.Field<Int32>("user_id") when CashOpeningsAssignments is Empty.
I tried moving the .DefaultIfEmpty() into users but still not working, Any idea how i can solve this?
Answer
Use the overload of DefaultIfEmpty to create an empty item.
E.g.
into_cashopeningsassignments
.DefaultIfEmpty(new CashOpeningsAssignments())
Running Code
The code reflects what you're trying to do, even though I took some liberties with it. For instance, I used List<T> instead of DataTable, because I did not figure out how to use Field<T>(string name) in a DotNetFiddle.
It's live here: https://dotnetfiddle.net/YaAc6D
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var query =
from Cash
in _DataTable_Cash.AsEnumerable()
join CashOpeningsAssignments
in _DataTable_CashOpeningsAssignments.AsEnumerable()
.Where(a =>
(a.cashopeningassignmentstatus_id == 1 ||
a.cashopeningassignmentstatus_id == 2))
on Cash.cash_id
equals CashOpeningsAssignments.cash_id
into into_cashopeningsassignments
from CashOpeningsAssignments
in into_cashopeningsassignments.DefaultIfEmpty(new CashOpeningsAssignments())
join Users
in _DataTable_Users.AsEnumerable()
on CashOpeningsAssignments.user_id
equals Users.user_id
into into_users
from Users
in into_users.DefaultIfEmpty()
select new
{
cash_id = Cash.cash_id,
// cellar_name = Cellars.cellar_name,
cash_name = Cash.cash_name,
// cashstatus_name = CashStatus.cashstatus_name,
user_name = (Users == null ? "[No Data]" : Users.user_firstname + (Char)32 + Users.user_lastname),
cashtransaction_amount = (Cash.cashstatus_id == 2 ? 0.00 : 150.00)
};
foreach(var result in query)
{
Console.WriteLine(result);
}
}
public static List<Cash> _DataTable_Cash =
new List<Cash> { new Cash() };
public static List<Cellars> _DataTable_Cellars =
new List<Cellars> { new Cellars() };
public static List<CashStatus> _DataTable_CashStatus =
new List<CashStatus> { new CashStatus() };
public static List<CashOpeningsAssignments> _DataTable_CashOpeningsAssignments =
new List<CashOpeningsAssignments> { };
public static List<Users> _DataTable_Users =
new List<Users>() { new Users() };
}
public class Cash
{
public int cash_id { get; set; }
public string cash_name { get; set; }
public int cellar_id { get; set; }
public int cashstatus_id { get; set; }
}
public class Cellars
{
public string cellar_name { get; set; }
public int cellar_id { get; set; }
}
public class CashStatus
{
public int cashstatus_id { get; set; }
public string cashstatus_name { get; set; }
}
public class CashOpeningsAssignments
{
public int user_id { get; set; }
public int cash_id { get; set; }
public int cashopeningassignmentstatus_id { get; set; }
}
public class Users
{
public string user_firstname { get; set; }
public string user_lastname { get; set; }
public int user_id { get; set; }
}
See Also
https://msdn.microsoft.com/en-us/library/vstudio/bb355419%28v=vs.100%29.aspx

Statement is not updating data item

I have this LINQ statement that tries to set the 1st element in the collection of string[]. But it doesn't work.
Below is the LINQ statement.
docSpcItem.Where(x => x.DocID == 2146943)
.FirstOrDefault()
.FinishingOptionsDesc[0] = "new value";
public string[] FinishingOptionsDesc
{
get
{
if (this._FinishingOptionsDesc != null)
{
return (string[])this._FinishingOptionsDesc.ToArray(typeof(string));
}
return null;
}
set { this._FinishingOptionsDesc = new ArrayList(value); }
}
What's wrong with my LINQ statement above?
Couple of things.. There are some problems with your get and set. I would just use auto properties like this..
public class DocSpcItem
{
public string[] FinishingOptionsDesc { get; set; }
public int DocID { get; set; }
}
Next for your linq statement, depending on the presence of an item with an id of 2146943 you might be setting a new version of the object rather than the one you intended. This should work..
[TestMethod]
public void Linq()
{
var items = new List<DocSpcItem>();
//2146943
for (var i = 2146930; i <= 2146950; i++)
{
items.Add(new DocSpcItem()
{ DocID = i
, FinishingOptionsDesc = new string[]
{ i.ToString() }
}
);
}
var item = items.FirstOrDefault(i => i.DocID == 2146943);
if (item != null)
{
item.FinishingOptionsDesc = new string[]{"The New Value"};
}
}
and
public class DocSpcItem
{
public string[] FinishingOptionsDesc { get; set; }
public int DocID { get; set; }
}

How to transform 2-levels-deep foreach loop to LINQ expression to produce Dictionary<string,SomeList<Item>>?

How do I transform this function:
void MyFunc () {
foreach (var k in problems.Keys)
{
var list = new ObservableCollection<ListViewItem>();
listViewItems.Add(k, list);
foreach (var i in problems[k].Items)
{
list.Add(new ListViewItem
{
Token = i.Token,
IsFatalError = i.IsFatal,
Checked = false,
Line = i.Token.Position.Line,
Description = i.Description,
BackgroundBrush = i.IsFatal ? Brushes.Red : null
});
}
}
}
to LINQ query syntax ? here are the types and variables:
public class ProblemsList {
public class Problem {
public IToken Token { get; set; }
public string Description { get; set; }
public bool IsFatal { get; set; }
}
public List<Problem> Items { get { return problems; } }
}
public class ListViewItem {
public bool IsFatalError { get; set; }
public bool Checked { get; set; }
public int Line { get; set; }
public string Description { get; set; }
public Brush BackgroundBrush { get; set; }
}
Dictionary<string, ProblemsList> problems;
Dictionary<string, ObservableCollection<ListViewItem>> listViewItems
= new Dictionary<string, ObservableCollection<ListViewItem>>();
Here's how I would do it (using chained methods syntax):
listViewItems = problems.ToDictionary(
p => p.Key,
p => new ObservableCollection<ListViewItem>(
p.Value.Items.Select(
i => new ListViewItem
{
Token = i.Token,
IsFatalError = i.IsFatal,
Checked = false,
Line = i.Token.Position.Line,
Description = i.Description,
BackgroundBrush = i.IsFatal ? Brushes.Red : null
}
)
)
);
Update
A version that uses query syntax as much as possible:
listViewItems = (
from p in problems
select new
{
Key = p.Key,
Value = from i in p.Value.Items
select new ListViewItem
{
Token = i.Token,
IsFatalError = i.IsFatal,
Checked = false,
Line = i.Token.Position.Line,
Description = i.Description,
BackgroundBrush = i.IsFatal
? Brushes.Red
: null
}
}
).ToDictionary(x => x.Key, x => x.Value);

Categories