Combine two lists and match values - c#

Inside the "Distributions" variable is a key called "Deadline" which contains a date.
I would like to add "RealDeadline = i.Deadline,". All the other lines works fine, but I just cant find a way to add the last thing.
The match has to be made on AssignmentId which is the key for the whole combine. basically if the HandInData.Where(...) could just add the value of "Deadline" from "Distributions", that would do the trick..
var HandInData = db.Handins.ToList();
var Distributions = db.Distributes.ToList();
var AssignNames = HandInData.Where(a => Distributions.Any(x => x.AssignmentId == a.AssignmentId));
var StudentsHandedInDataFeed = AssignNames.Select(i => new {
*RealDeadline = i.Deadline, (this is not working..)*
Help = i.NeedHelp,
Done = i.Done,
AssName = i.Assignment.AssignmentName,
Student = i.Student.StudentName,
DeadlineInTimeformat = i.Assignment.AssignmentDeadline,
HandedInInTimeformat = i.HandedInDate,
Deadline = i.Assignment.AssignmentDeadline.ToString(),
HandedIn = i.HandedInDate.ToString()
});
public class Handin {
public int HandinId { get; set; }
public int StudentId { get; set; }
public int AssignmentId { get; set; }
public bool? Done { get; set; }
public bool? NeedHelp { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime? HandedInDate { get; set; }
public virtual Student Student { get; set; }
public virtual Assignment Assignment { get; set; }
}

You need to join the two lists. You can do it with LINQ syntax like this:
var StudentsHandedInDatFeed =
from h in HandInData
join d in Distributions on h.AssignmentId equals d.AssignmentId
select new {
RealDeadline = d.Deadline,
Help = h.NeedHelp,
// etc
};
The join will only include values from HandInData where there is a matching value in Distributions, so this takes care of your Where(a => Distributions.Any(... code as well.

Related

C# group by a column and form hierarchical data with other columns

I am trying to group a column and form the the rest of the columns as child, hierarchical data:
I am trying to group by Code and form the parent and child relationship from a flat list, below is the hierarchical data I am trying to form:
source list:
public class ItemAssignmentFlatList
{
public int Code { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public int ItemCode{ get; set; }
public DateTime EffectiveDate{ get; set; }
public string Area{ get; set; }
public string TaxCode{ get; set; }
public string LocationId { get; set; }
}
Need to convert above flat list into below List of hierarchical data:
public class ItemInfo
{
public int Code { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public List<TaxInfo> TaxPlan { get; set; }
}
public class TaxPlan
{
public int ItemCode{ get; set; }
public DateTime EffectiveDate{ get; set; }
public string Area{ get; set; }
public string TaxCode{ get; set; }
public string LocationId { get; set; }
}
Need hierarchical list with above flat data list with C# extension methods.
I have below code, but looking for clean code to reduce number of lines:
var items= results.GroupBy(x => new { x.Code, x.Type });
List<ItemInfo> result = new List<ItemInfo>();
foreach (var group in items)
{
var taxPlans = group.
Select(y => new TaxPlan
{
TaxArea = y.TaxArea,
ItemCode = y.ItemCode
});
var itemInfo= new ItemInfo
{
Code = group.FirstOrDefault().Code,
Type = group.FirstOrDefault().Type,
Description = group.FirstOrDefault().Description,
TaxPlan = taxPlans.ToList()
};
result.Add(itemInfo);
}
Something like this?:
var input = new List<ItemAssignmentFlatList>(){
new ItemAssignmentFlatList{
Code = 1,
Area = "a"
},
new ItemAssignmentFlatList{
Code = 1,
Area = "b"
},
new ItemAssignmentFlatList{
Code = 2,
Area = "c"
}
};
input
.GroupBy(
x => x.Code,
(int code, IEnumerable<ItemAssignmentFlatList> items) =>
{
var first = items.FirstOrDefault();
var key = new ItemInfo
{
Code = first.Code
//, ...
};
var plan = items.
Select(y => new TaxPlan
{
Area = y.Area
//, ...
});
return new
{
key = key,
items = plan
};
}
).Dump();
Whenever you have a sequence of similar object, and you want to make "Items with their SubItems", based on common properties in your source sequence, consider to use one of the overloads of Enumerable.GroupBy
Because you don't just want "Groups of source items" but you want to specify your output, consider to use the overload that has a parameter resultSelector.
parameter keySelector: what should all elements in a group have in common
parameter resultSelector: use the common thing, and all elements that have this common thing to make one output element.
.
IEnumerable<ItemAssignmentFlatList> flatItemAssignments = ...
IEnumerable<ItemInfo> items = flatItemAssignments
// make groups with same {Code, Type, Description}
.GroupBy(flatItemAssignment => new {Code, Type, Description},
// parameter resultSelector: take the common CodeTypeDescription,
// and all flatItemAssignments that have this common value
// to make one new ItemInfo
(codeTypeDescription, flatItemAssignmentsWithThisCodeTypeDescription) => new ItemInfo
{
Code = codeTypeDescription.Code,
Type = codeTypeDescription.Type,
Description = codeTypeDescription.Description,
TaxPlans = flatItemAssignmentsWithThisCodeTypeDescription
.Select(flatItemAssignment => new TaxPlan
{
ItemCode = flatItemAssignment.ItemCode,
EffectiveDate = flatItemAssignment.EffectiveDate,
Area = flatItemAssignment.Area,
...
})
.ToList(),
});

How do I negotiate joins and groupings based on nested properties in LINQ?

So I've got a nested data structure like this:
public class ContractTerm
{
public int ContractId { get; set; }
public string SectionId { get; set; }
public string SubsectionId { get; set; }
public string TermId { get; set; }
public int TermOrder { get; set; }
public TermItem TermNavigation { get; set; }
}
public class TermItem
{
public string SectionId { get; set; }
public string SubsectionId { get; set; }
public string TermId { get; set; }
public string Text { get; set; }
public ICollection<ContractTerm> ContractNavigation { get; set; }
}
I've also got a class to map the section/subsection pairings in a more EF-friendly way (IRL this is an enum with attribute values and a helper, but this class abstracts away some work not necessary to reproduce the issue):
public class Section
{
public string Name { get; set; }
public string SectionId { get; set; }
public string SubsectionId { get; set; }
}
Both ContractTerm and TermItem have their own collections in a DbContext, and I'm trying to get a collection of all text entries assigned to specific Sections for a given ContractId. I have the following class to contain it:
public class TextsBySection
{
public string SectionName { get; set; }
public IEnumerable<string> Texts { get; set; }
}
I want to select a collection of TextsBySection, and have something like this:
public class ContractManager
{
//insert constructor initializing MyContext here
private MyContext Context { get; }
public IEnumerable<MyOutputClass> GetTerms(int contractId, IEnumerable<Section> sections)
{
Func<string, string, IEnumerable<string>> getBySection =
(section, subsection) => context.ContractTerms.Include(x => x.TermNavigation)
.Where(x => x.ContractId == contractId
&& x.SectionId == section
&& x.SubsectionId == subsection)
.Select(x => x.TermNavigation.Text);
var result = sections.Select(x => new MyOutputClass
{
SectionName = x.Name,
Texts = getBySection(x.SectionId, x.SubsectionId)
}).ToList();
return result;
}
}
This works fine and dandy, but it hits the database for every Section. I feel like there's got to be a way to use Join and/or GroupBy to make it only query once, but I can't quite see it. Something like this, perhaps:
var result = context.ContractTerms.Include(x => x.TermNavigation)
.Where(x => x.ContractId == contractId)
.Join(sections,
term => //something
section => //something
(term, section) => /*something*/)
If all this were in SQL, selecting the necessary data would be easy:
SELECT sections.name,
term_items.text
FROM contract_terms
JOIN term_items
ON term_items.section_id = contract_terms.section_id
AND term_items.subsection_id = contract_terms.subsection_id
AND term_items.term_id = contract_terms.term_id
JOIN sections --not a real table; just corresponds to sections argument in method
ON sections.section_id = contract_terms.section_id
AND sections.subsection_id = contract_terms.subsection_id
...and then I could group the results in .NET. But I don't understand how to make a single LINQ query that would do the same thing.
I changed my answer, well I would do something like this... maybe this may help you.
public static void Main(string[] args)
{
List<Section> sections = new List<Section>();
List<ContractTerm> contractTerms = new List<ContractTerm>();
List<TermItem> termItens = new List<TermItem>();
//considering lists have records
List<TextsBySection> result = (from contractTerm in contractTerms
join termItem in termItens
on new
{
contractTerm.SectionId,
contractTerm.SubsectionId,
contractTerm.TermId
}
equals new
{
termItem.SectionId,
termItem.SubsectionId,
termItem.TermId
}
join section in sections
on new
{
contractTerm.SectionId,
contractTerm.SubsectionId
} equals new
{
section.SectionId,
section.SubsectionId
}
select
new
{
sectionName = section.Name,
termItemText = termItem.Text
}).GroupBy(x => x.sectionName).Select(x => new TextsBySection()
{
SectionName = x.Key,
Texts = x.Select(i=> i.termItemText)
}).ToList();
}

Possible to add a condition for linked table fields in LINQ

Can someone suggest me a solution to add condition for reference table items in linq.
I have a master table called TourPackage, which include
public class TourPackage{
public int TourID { get; set; }
public string TourName { get; set; }
public List<IncludedItems> IncludedItems { get; set; }
}
Every tour package contain some selected items reference like
public class IncludedItems {
public int TourID { get; set; }
public int IncludedID { get; set; }
public Included Included { get; set; }
}
All included item should have a reference to Included table for lookup reference
public class Included {
public int IncludedID { get; set; }
public string IncludedValue { get; set; }
}
now i have set of IncludedID like [1,2,3], Is it possible to filter TourPackage based on IncludedID.
Thanks in advance
You can use following code
I have sample array(i.e example) which contains ID's we check if current Id(i.e ele.Included.IncludedID) is present in the array of id's.
listex.Where(x => x.IncludedItems.Any(ele => example.Contains(ele.Included.IncludedID))).ToList();
sample:-
int[] example = new int[3];
example[0] = 123;
example[1] = 456;
example[2] = 789;
List<TourPackage> listex = new List<TourPackage>();
List<TourPackage> filterList = listex.Where(x => x.IncludedItems.Any(ele => example.Contains(ele.Included.IncludedID))).ToList();
Have you tried using something like:
var myIds = new List<int> {123,456};
var result = context.TourPackages
.Where(x => x.IncludedItems.Any(a => a.Included !=null && myIds.Contains(a.Included.IncludedId)))
.ToList();
You might have to include some relations manually depending if you're lazy loading is setup or not.
More info at https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx

Linq Join with Clone

I have a sequence of objects, whose type has many properties and I would like to join it with another sequence and set a value taking from the second sequence. But because there are many properties I do not prefer to create a new anonymous type by doing all those property assignments. Is there a better way to do this in a single linq query (having been trying un-successfully with let)
var x = from lt in legalTerms
join le in legalEntities on lt.LegalEntityCode equals le.Code
select new {a = lt.a, b = lt.b, c = le.c, d = lt.d .... z=lt.z} // don't like
I need a sequence like legalTerms where the items have that one property updated from legalEntities
Wish there was somehow a way to clone le and set that one property c = le.c without using reflection etc
Basically this is what I wonder is possible in a linq statement
foreach (var lt in legalTerms)
{
foreach (var le in legalEntities)
{
if (le.Code == lt.LegalEntityCode)
{
lt.LegalEntity = le.Name;
}
}
}
how about this
var map = new Func<LegalTerm, LegalEntity, LegalTerm>((term, entity) =>
{
term.LegalEntity = entity.Name;
return term;
});
var query = from lt in legalTerms
join le in legalEntities
on lt.Code equals le.LegalEntityCode
select map(lt, le);
knowing that you have some sort of structures similar to those bellow
public class LegalTerm
{
public string Code { get; set; }
public string LegalEntity { get; set; }
public string a { get; set; }
public string b { get; set; }
public string c { get; set; }
public string d { get; set; }
}
public class LegalEntity
{
public string LegalEntityCode { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}

Inner join not working when use equal with %, What an alternative way to use it like like %

I have Medals class, I call a service that return all Medal class fields except for the two fields ArabicName and ISOCode; Which I have to bring them from another table class "CountrysTBLs" , I made this join code:
The Medal class:
public class Medals {
public int bronze_count { get; set; }
public string country_name { get; set; }
public int gold_count { get; set; }
public string id { get; set; }
public int place { get; set; }
public int silver_count { get; set; }
public int total_count { get; set; }
public string ArabicName { get; set; } // this field not return by service
public string ISOCode { get; set; } // this field not return by service
}
The code:
var cntrs = db.CountrysTBLs.ToList();
List<Medals> objs = call_Service_Of_Medals_Without_ISOCode();
IEnumerable<Medals> query = from obj in objs
join cntry in cntrs on obj.country_name equals '%' + cntry.CommonName + '%'
select new Medals
{
ArabicName = cntry.ArabicName,
ISOCode = cntry.ISOCode,
country_name = obj.country_name,
place = obj.place,
gold_count = obj.gold_count,
silver_count = obj.silver_count,
bronze_count = obj.bronze_count,
total_count = obj.total_count
};
I get no result?!
How to fix that? Is there is any way to bring the two fields (ISOCode, ArabicName) without even use the inner join, and in same time best performance?
You want something like this to achieve LIKE functionality
List<Medals> medals = new List<Medals>();
var list = medals.Select(x => new
{
obj = x,
country = countries.FirstOrDefault(c => c.CommonName.Contains(x.country_name))
});
or something like this (if you want to just enrich each medal)
foreach (var medal in medals)
{
var country = countries.FirstOrDefault(c => c.CommonName.Contains(x.country_name));
medal.ISOCode = country.ISOCode;
medal.ArabicName = country.ArabicName;
}
Do note that this is not as performant as a Dictionary<string,Coutnry> of countries where the key is the country name, but as you need a LIKE comparison you would need to bring in a custom data structure such as Lucene index for fast lookups. But check first, if the lists are small enough, it probably won't be a problem. Otherwise, why not make the Medal.Country_Name and Country.Name the same? So you can do quick Dictionary (hashtable) lookups

Categories