Why does this Linq left outer join not work as expected? - linq

I have two lists, both using the same class (Part). The first list is the "master" list (engineerParts), the second (partDefaults) is the list of attribute values for those parts.
The first list contains 263 items, the second, 238. So, the final list should contain 263. However it doesn't, it contains 598!!
var partsWithDefaults = from a in engineerParts
join b in partDefaults on
new { a.PartNumber, a.Revision }
equals
new { b.PartNumber, b.Revision } into j1
from j2 in j1.DefaultIfEmpty()
select new Part()
{
NewPart = isNewPart(a.PartNumber, PadRevision(a.Revision), concatenateRevision),
PartNumber = concatenateRevision == true ? string.Concat(a.PartNumber, PadRevision(a.Revision)) : a.PartNumber,
Revision = concatenateRevision == true ? "" : a.Revision,
ParentPart = a.ParentPart,
Description = a.Description,
BoMQty = a.BoMQty,
UoM = (j2 != null) ? j2.UoM : null,
ClassId = (j2 != null) ? j2.ClassId : null,
ShortDescription = (j2 != null) ? j2.ShortDescription : null,
ABCCode = (j2 != null) ? j2.ABCCode : null,
BuyerId = (j2 != null) ? j2.BuyerId : null,
PlannerId = (j2 != null) ? j2.PlannerId : null,
OrderPolicy = (j2 != null) ? j2.OrderPolicy : null,
FixedOrderQty = (j2 != null) ? j2.FixedOrderQty : null,
OrderPointQty = (j2 != null) ? j2.OrderPointQty : null,
OrderUpToLevel = (j2 != null) ? j2.OrderUpToLevel : null,
OrderQtyMin = (j2 != null) ? j2.OrderQtyMin : null,
OrderQtyMax = (j2 != null) ? j2.OrderQtyMax : null,
OrderQtyMultiple = (j2 != null) ? j2.OrderQtyMultiple : null,
ReplenishmentMethod = (j2 != null) ? j2.ReplenishmentMethod : null,
ItemShrinkageFactor = (j2 != null) ? j2.ItemShrinkageFactor : null,
PurchasingLeadTime = (j2 != null) ? j2.PurchasingLeadTime : null,
MFGFixedLeadTime = (j2 != null) ? j2.MFGFixedLeadTime : null,
PlanningTimeFence = (j2 != null) ? j2.PlanningTimeFence : null,
FulfillMethod = (j2 != null) ? j2.FulfillMethod : null,
ItemStatus = (j2 != null) ? j2.ItemStatus : null,
TreatAsEither = (j2 != null) ? j2.TreatAsEither : false,
AltItem1 = (j2 != null) ? j2.AltItem1 : null,
AltItem2 = (j2 != null) ? j2.AltItem2 : null,
AltItem3 = (j2 != null) ? j2.AltItem3 : null,
AltItem4 = (j2 != null) ? j2.AltItem4 : null,
AltItem5 = (j2 != null) ? j2.AltItem5 : null,
DesignAuthority = (j2 != null) ? j2.DesignAuthority : null,
Level = a.Level
};
return partsWithDefaults.ToList<Part>();

Turns out it was a data issue. The person that had sent me the data in Excel for the second list had left duplicates in it!!!!

Related

.net core Entity Framework The nested query is not supported. Operation1='Case' Operation2='Collect'

I have a following query for some nested implementation
return _context.baseTable1.Where(h => h.id == Id ).Select(lev => new
{
Contact = (lev.baseTable2 != null
&& lev.baseTable2.baseTable3 != null
&& lev.baseTable2.baseTable3.baseTable5.Any(h => h.contact != null)
? lev.baseTable2.baseTable3.baseTable5.Where(h => h.contact != null).GroupBy(h => h.contact).Select(c=>c.FirstOrDefault().contact) : null),
Key1 = lev.office != null ? lev.office.id, : null,
Key2 = lev.baseTable2 != null && lev.baseTable2.baseTable3 != null && lev.baseTable2.baseTable3.baseTable4 != null ?
lev.baseTable2.baseTable3.baseTable4.id : null
}).ToList().SelectMany(x =>
{
if (!x.Contact.Any())
{
return new List<FinalModel> { new FinalModel { Key1 = x.Key1, Key2 = x.Key2 } };
}
else
return x.Contact.Select(contact => new FinalModel()
{
ContactKey = contact.id,
Key1 = x.Key1,
Key2 = x.Key2
});
});
It was created via help from
GroupBy then Select with conditional record addition
But now getting above error

Linq To Select All controls where DI contains some text from ControlCollection

Linq has always befuddled me. I am trying to extract all controls from an ASP.Net form page where the ID of the control contains a specific string. The control collection is hierarchical and I want to return any matching controls from all levels. Am I anywhere in the ballpark here? I could really use some help/education. The collection parameter is the collection of controls from the page and controlID is the text I am searching for.
public static Control FindControlsByControlID(ControlCollection collection, string controlID)
{
IEnumerable<Control> controls = collection.Cast<Control>();
IEnumerable<Control> matchedControls = controls
.SelectMany(p => p.Controls.Cast<Control>()
.SelectMany(c => c.Controls.Cast<Control>())
.Where(d => d != null ? d.ID != null ? d.ID.Contains(controlID) : false : false))
.Where(a => a != null ? a.ID != null ? a.ID.Contains(controlID) : false : false);
ConcurrentQueue<Control> cq;
if (matchedControls != null)
cq = new ConcurrentQueue<Control>(matchedControls);
else
return null;
...
Thanks in advance!
Use an extension method to get all child controls:
public static class ControlExt {
public static IEnumerable<Control> AndSubControls(this Control aControl) {
var work = new Queue<Control>();
work.Enqueue(aControl);
while (work.Count > 0) {
var c = work.Dequeue();
yield return c;
foreach (var sc in c.Controls.Cast<Control>()) {
yield return sc;
if (sc.Controls.Count > 0)
work.Enqueue(sc);
}
}
}
}
Now you can test all the subcontrols in your ControlCollection:
IEnumerable<Control> matchedControls = controls.SelectMany(c => c.AndSubControls())
.Where(a => a != null && a.ID != null && a.ID.Contains(controlID));

How to make the given method generic ? Is it a good idea to make it generic in terms of performance?

private IQueryable<Customer> FilterResult(string search, List<Customer> dtResult, List<string> columnFilters)
{
IQueryable<Customer> results = dtResult.AsQueryable();
results = results.Where(p =>
(
search == null ||
(
p.Name != null && p.Name.ToLower().Contains(search.ToLower())
|| p.City != null && p.City.ToLower().Contains(search.ToLower())
|| p.Postal != null && p.Postal.ToLower().Contains(search.ToLower())
|| p.Email != null && p.Email.ToLower().Contains(search.ToLower())
|| p.Company != null && p.Company.ToLower().Contains(search.ToLower())
|| p.Account != null && p.Account.ToLower().Contains(search.ToLower())
|| p.CreditCard != null && p.CreditCard.ToLower().Contains(search.ToLower())
)
)
&& (columnFilters[0] == null || (p.Name != null && p.Name.ToLower().Contains(columnFilters[0].ToLower())))
&& (columnFilters[1] == null || (p.City != null && p.City.ToLower().Contains(columnFilters[1].ToLower())))
&& (columnFilters[2] == null || (p.Postal != null && p.Postal.ToLower().Contains(columnFilters[2].ToLower())))
&& (columnFilters[3] == null || (p.Email != null && p.Email.ToLower().Contains(columnFilters[3].ToLower())))
&& (columnFilters[4] == null || (p.Company != null && p.Company.ToLower().Contains(columnFilters[4].ToLower())))
&& (columnFilters[5] == null || (p.Account != null && p.Account.ToLower().Contains(columnFilters[5].ToLower())))
&& (columnFilters[6] == null || (p.CreditCard != null && p.CreditCard.ToLower().Contains(columnFilters[6].ToLower())))
);
return results;
}
This is the method which I am using for datatable filter , Here my question is can I make it as generic ? I feel it can be using reflection. But does that affect to performance as well ?
thx in advance..
I have done till it so far :
private IQueryable<T> FilterResult<T>(string search, IQueryable<T> dtResult, List<string> columnFilters)
{
IQueryable<T> results = dtResult;
Type typeParameterType = typeof(T); // this will give me the class detail which I have passed
// 1 How to extract all property of this class to use in where clause
// 2 How I can use it either dynamic linq , foreach or any possible solution.
//1
PropertyInfo[] properties = typeParameterType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var item in properties)
{
// This will be changed after some validation logic
string predicate = item.Name + " = " + search;
results = results.Where(predicate);
}
return results;
}
I'm not familiar (and don't intend to use) dynamic LINQ. In this case you don't really need such thing. As I said I would not pass in a list of string as column filters, it makes code longer and the order can matter and cause hard-to-debug issues. Here is the code I've just come up with, you can try and I'm not sure it works but if any please let me know:
private IEnumerable<T> FilterResult<T>(string search, IQueryable<T> dtResult, params ColumnFilter<T>[] filters)
{
var propGetters = typeof(T).GetProperties().Where(p => p.PropertyType == typeof(string))
.Select(p => new Func<object,string>((item) => ((p.GetValue(item, null) as string) ?? "").ToLower())).ToList();
if(!string.IsNullOrEmpty(search)) {
Func<T,bool> predicate = e => propGetters.Aggregate(false, (c,o) => c || o(e));
dtResult = dtResult.Where(predicate).AsQueryable();
}
return filters.Aggregate(dtResult.AsEnumerable(), (c,e) => c.Where(o => e.IsOK(o));
}
public class ColumnFilter<T> {
public ColumnFilter(Func<T,string> selector, string term = ""){
PropertySelector = selector;
Term = term;
}
public Func<T,string> PropertySelector {get;set;}
public string Term {get;set;}
public bool IsOK(T item) {
return PropertySelector(item).Contains(Term);
}
}
Usage:
FilterResult(yourSearch, yourDtResult, new ColumnFilter(e=>e.City, "someCitySearch"),
new ColumnFilter(e=>e.Postal, "somePostalSearch"), ...);
If you still want to stick to List for columnFilters, the code can be modified but it will be surely longer.

How to format data value

I have the following Linq to Sql:
var subscribers = (from s in dataContext.Employees
where s.RowType == "Edit"
select new SubscriberExportData
{
ID = s.ID.ToString(),
GroupNum = s.GroupNumber,
DivisionNum = s.DivisionNumber,
HireDate = s.HireDate != null ? Convert.ToDateTime(s.HireDate).ToShortDateString() : string.Empty,
EffDate = s.EffectiveDate != null ? Convert.ToDateTime(s.EffectiveDate).ToShortDateString() : string.Empty
}
Essentially, if the date value is not null then convert them to short date format. But I am getting the following error:
System.InvalidOperationException was unhandled
Message=Could not translate expression 'Table(Employee).Where(s => (s.RowType == "Edit")).Select(s => new SubscriberExportData() { HireDate = IIF((s.HireDate != null), ToDateTime(Convert(s.HireDate)).ToShortDateString(), Invoke(value(System.Func`1[System.String]))), EffDate = IIF((s.EffectiveDate != null), ToDateTime(Convert(s.EffectiveDate)).ToShortDateString)' into SQL and could not treat it as a local expression.
Source=System.Data.Linq
Please let me know how to resolve it.
You can split the query into two, the first being operations that sql understands and the second being the string conversions that will be performed locally
var list = (from s in dataContext.Employees
where s.RowType == "Edit"
select new
{
s.ID
s.GroupNumber,
s.DivisionNumber,
s.HireDate
s.EffectiveDate
}).ToList();
var subscribers = (from s in list
select new SubscriberExportData
{
ID = s.ID.ToString(),
GroupNum = s.GroupNumber,
DivisionNum = s.DivisionNumber,
HireDate = s.HireDate != null ? Convert.ToDateTime(s.HireDate).ToShortDateString() : string.Empty,
EffDate = s.EffectiveDate != null ? Convert.ToDateTime(s.EffectiveDate).ToShortDateString() : string.Empty
}

Search in MVC3 asp.net condition failed always

i've a action SearchPost. in the get action:
ViewBag.cities = db.cities.ToList();
ViewBag.areas = db.areas.ToList();
IEnumerable<SelectListItem> Months =pm.GetMyMonthList().Select(a => new
SelectListItem {
Value = a.Value,
Text = a.Text
}).ToList();
ViewBag.monthList = Months;
IEnumerable<SelectListItem> rentTypes = pm
.GetRentType()
.Select(a => new SelectListItem
{
Value = a.Value,
Text = a.Text
})
.ToList();
ViewBag.typeList = rentTypes;
return View(db.posts.Include("user").ToList());
in the view page
#Html.DropDownList("City",new SelectList(ViewBag.cities as
System.Collections.IEnumerable, "city_id", "name"),
"Select City", new { id = "ddlCars" })
#Html.DropDownList("Area", new SelectList(Enumerable.Empty<SelectListItem>(),
"area_id", "name"),
"Select Area", new { id = "ddlModels" })
#Html.DropDownList("rent_type", new SelectList(ViewBag.typeList as
System.Collections.IEnumerable, "Value", "Text"), "Select Category")
#Html.DropDownList("month", new SelectList(ViewBag.monthList as
System.Collections.IEnumerable, "Value", "Text"), "Select Month")
in my Post action:
IList<post> p = db.posts.Include("user").ToList();
string Area = Request.Form["Area"];
string City = Request.Form["City"];
if (City != "Select City" && City != null && City !="")
{
int c_id = Convert.ToInt32(City);
city c = db.cities.Single(s => s.city_id == c_id);
ci = c.name;
}
if (Area != "Select Area" && Area != null && Area !="")
{
int a_id = Convert.ToInt32(Area);
area a = db.areas.Single(x => x.area_id == a_id);
ar = a.name;
}
string rent_type = Request.Form["rent_type"];
string month = Request.Form["month"];
if (rent_type != null && rent_type != "")
{
if ((p != null) && (p.Any()))
{
p = p.Where(a => a.rent_type == rent_type).ToList();
}
}
if (month!= null && month != "")
{
if ((p != null) && (p.Any()))
{
p = p.Where(a => a.rent_month == month).ToList();
}
}
return View(p);
here i've select all posts from my database first. then i want to filter it by city,area, month and rent_type. City and area are cascade dropdownlist.when i select city and area it filter records correctly. but if i select only city it gives error: Sequence contains no elements at the line:
area a = db.areas.Single(x => x.area_id == a_id);
and when i try to filter by only month or rent_type it didn't filter records and always give no records. in which part of code should i change for solve those two problems... thanks in advance...

Resources