LINQ left self join - c#

I have LINQ query as below:
lst_direct_managers = context.sf_guard_user_profile
.Join(context.sf_guard_user_profile, up => up.user_id, dm => dm.direct_manager_id,
(up, dm) => new { up, dm })
.Where(m => m.up.is_gvo == 1)
.Select(m => new DirectManagerModel
{
user_id = m.up.direct_manager_id == null ? 0 : m.up.direct_manager_id,
dm_full_name = (m.up.first_name + " " + m.up.last_name == null ? "No Direct Manager" : m.up.first_name + " " + m.up.last_name)
})
.Distinct()
.OrderBy(m => m.dm_full_name).ToList();
Problem is that it does not return default value in case of nulls "No Direct Manager". Can you please help me?

Related

List<object>: how to apply a "where" for some index element?

I've this kind of List of object:
.AsEnumerable().Select(p => new List<object>()
{
p.ID,
p.DateActivity.HasValue ? p.DateActivity.Value.ToString("yyyyMMdd") : null,
p.DateActivity.HasValue ? p.DateActivity.Value.Month.ToString() : null,
p.DateActivity.HasValue ? p.DateActivity.Value.Year.ToString() : null,
p.Clinic.ID,
p.Clinic.Name,
p.Patient.LastName + " " + p.Patient.FirstName,
p.Patient.Gold,
p.Patient.PromoSmiles,
p.TreatmentType.Description ?? "",
p.PaymentMethod.Description ?? "",
p.ActivityPayments.Select((q, index) => new
{
Description = q.PaymentTypeID == (int)PaymentType.ACCONTO ? labelAcconto : q.PaymentTypeID == (int)PaymentType.SINGOLOPAGAMENTO && p.PaymentMethod.ID == 1 ? labelRata + (index - p.ActivityPaymentsNonSinglePaymentCount + 1) : labelImporto,
Amount = q.Amount,
Date = q.Date,
Paid = q.Paid
})
}).ToList();
The last item (i.e. data[11]) is a list of objects.
I want to apply a Where before the .ToList(), so that it filters only objects of data where data[11] list have at least one Paid = true.
How can I do it?
Two solutions:
Cast data[11] to IEnumerable<dynamic>
.Where(data => ((IEnumerable<dynamic>)data[11])
.Any(q => q.Paid))
Apply Where before Select
.AsEnumerable()
.Where(p => p.ActivityPayments.Any(q => q.Paid))
.Select(...)
Just use an anonymous object instead of a list of objects in the first Select method.
var data = .AsEnumerable().Select(p => new
{
p.ID,
p.DateActivity.HasValue ? p.DateActivity.Value.ToString("yyyyMMdd") : null,
p.DateActivity.HasValue ? p.DateActivity.Value.Month.ToString() : null,
p.DateActivity.HasValue ? p.DateActivity.Value.Year.ToString() : null,
p.Clinic.ID,
p.Clinic.Name,
p.Patient.LastName + " " + p.Patient.FirstName,
p.Patient.Gold,
p.Patient.PromoSmiles,
p.TreatmentType.Description ?? "",
p.PaymentMethod.Description ?? "",
p.ActivityPayments.Select((q, index) => new
{
Description = q.PaymentTypeID == (int)PaymentType.ACCONTO ? labelAcconto : q.PaymentTypeID == (int)PaymentType.SINGOLOPAGAMENTO && p.PaymentMethod.ID == 1 ? labelRata + (index - p.ActivityPaymentsNonSinglePaymentCount + 1) : labelImporto,
Amount = q.Amount,
Date = q.Date,
Paid = q.Paid
})
}).ToList();
var filteredData = data.where(x => x.ActivityPayments.Paid).ToList();

how to allow the user to choose how to sort his list using a variable?

the information that the user enters can be sorted in many ways ascending and descending and i'm trying to make the user choose how he want to see the data:
so is there any way to set a variable that the user enter and sort the data without repeating the code multiple time depending on the input like:
var empName = el.Select(i => new { i.ID, i.FullName });
if(emsort.Text="text1")
empName.OrderBy(i.text1);
else if...
by doing something shorter like:
string sort=emsort.Text ;
empName.OrderBy(sort);
If I understood your problem right, that you want to sort dynamically with the property name which is stored in emsort.Text, then you can use Expressions:
assuming empName is IEnumerable<Employee>, then use this:
private static Func<Employee, dynamic> GetSortable(string sortablePoperty)
{
var param = Expression.Parameter(typeof(Employee), "e");
var member = Expression.Property(param, sortablePoperty);
Expression memberAsObject = Expression.Convert(member, typeof(object));
return Expression.Lambda<Func<Employee, dynamic>>(memberAsObject, param).Compile();
}
then use it:
string sort=emsort.Text ;
empName.OrderBy(GetSortable(sort));
if empName is IQueryable<Employee>, then use this:
private static Expression<Func<Employee, dynamic>> GetSortable(string sortablePoperty)
{
var param = Expression.Parameter(typeof(Employee), "e");
var member = Expression.Property(param, sortablePoperty);
Expression memberAsObject = Expression.Convert(member, typeof(object));
return Expression.Lambda<Func<Employee, dynamic>>(memberAsObject, param);
}
If the User in your question is some software that calls your function, then the user is aware of the type of the objects in the el sequence: he knows which properties the elements in the el sequence are, and he knows how he wants them ordered.
Why not let this user give you the keySelector to use in the OrderBy?
Creating an extension function:
static class QueryableExtensions
{
IQueryable<MyType> SelectAndSort<TSource, TResult>(this IQueryable<TSource source,
Expression<Func<TSource, TResult>> selector,
Expression<Func<TSource, TKey>> sortKeySelector,
System.ComponentModel.ListSortDirection sortDirection)
{
var selectBeforeOrdering = myRepository.el.Select(selector);
// note: this is still an IQueryable, only the query has been made,
// the database is not accessed yet!
IQueryable<TResult> result = (sortDirection == ListSortDirectrion.Ascending) ?
// sort in ascending order:
selectBeforeOrdering.OrderBy(sortKeySelector) :
// else: selec in descending order:
selectBeforeOrdering.OrderByDescending(sortKeySelector);
return result;
}
}
Usage: suppose your user knows your el, and he want several fields of it, ordered by one of the properties of your el
using (var myDbContext = new DbContext(...))
{
IQueryable myEls = myDbContext.el;
var mySelectedItems = myEls.SelectAndSore(
// selector: what properties do I as a user want?
el => new
{
Id = el.Id,
FullName = el.FullName,
... // other desired properties
},
// sortSelector: how do I want my selected items to be sorted?
selectedItem => selectedItem.FullName,
// direction:
ListSortDirection.Descending);
// note: until now the database has not been accessed
// only the Expression of the query has been created.
// depending on what you want as a result: ToList / ToArray / First / ...
return mySelectedItems.ToList();
}
If, on the other hand your user is not software, but an operator, who has to select by which column he wants his items to be ordered, he has to have a method to tell the computer which column should be sorted.
This is usually done by clicking the column. Another method could be by selecting a value in a combo box. Anyway, you'll have to attach something to the column or to the combobox values that holds the sortKeySelector:
class MySortableColumn<TDisplayedProperty> : DataGridViewColumn
// or whatever column class you are using
{
public Expression<Func<MyDisplayedItem, TDisplayedProperty>> SortKeySelector{get;set;}
}
Now you have several columns that each display one of the properties of MyDisplayedItem:
var columnId = new MySortableColumn<int>()
{
SortKeySelector = displayedItem => myDisplayedItem.Id,
};
var columnFullName = new MyStortableColumn<string>()
{
SortKeySelector = displayedItem => myDisplayedItem.Id,
}
// etc.
Whenever the operator clicks on a column, the sortKey is extracted and used as parameter to sort the items:
void SortColumn(SortableColumn column)
{
var sortedItems = Sort(column.SortKeySelector, ListSortOrder...);
Display(sortedItems);
}
As I assume, el is materialized(i.e., for example, it is not just entry point to database), so you can use reflection:
var sort = emsort.Text;
PropertyInfo property = null;
var sortedData = el.Select(i => new { i.ID, i.FullName })
.OrderBy(x =>
{
property = property ?? x.GetType().GetProperty(sort);
return property.GetValue(x);
}).ToList();
this is a part of the code that i had to write to do it :
if (emord.Text == "Ascending")
{
if (emsort.Text == "ID")
{
var empName = el.Select(i => new { i.ID, i.FullName }).OrderBy(x => x.ID);
var empNamenAmp = el.Select(i => new { i.ID, i.FullName, i.Salary, i.Currency, i.Per }).OrderBy(x => x.ID);
var empNamenAmpnwh = el.Select(i => new { i.ID, i.FullName, i.Salary, i.Currency, i.Per, i.Hours }).OrderBy(x => x.ID);
var empNamenwh = el.Select(i => new { i.ID, i.FullName, i.Hours }).OrderBy(x => x.ID);
var empNamenbd = el.Select(i => new { i.ID, i.FullName, i.Date }).OrderBy(x => x.ID);
var empNamenad = el.Select(i => new { i.ID, i.FullName, i.Location }).OrderBy(x => x.ID);
var empNamenpn = el.Select(i => new { i.ID, i.FullName, i.PhoneNb }).OrderBy(x => x.ID);
var empNamena = el.Select(i => new { i.ID, i.FullName, i.Age }).OrderBy(x => x.ID);
if (empfilcomb.Text == "Name")
{
dispfil.Clear();
foreach (var x in empName)
dispfil.Text += x.ID + ", " + x.FullName + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Amount paid")
{
dispfil.Clear();
foreach (var x in empNamenAmp)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Salary + " " + x.Currency + " " + x.Per + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Work Hours")
{
dispfil.Clear();
foreach (var x in empNamenwh)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Hours + Environment.NewLine;
}
else if (empfilcomb.Text == "Name,Amount paid and Work Hours")
{
dispfil.Clear();
foreach (var x in empNamenAmpnwh)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Salary + " " + x.Currency + " " + x.Per + ", " + x.Hours + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Birthday")
{
dispfil.Clear();
foreach (var x in empNamenbd)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Date + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Address")
{
dispfil.Clear();
foreach (var x in empNamenad)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Location + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Phone Number")
{
dispfil.Clear();
foreach (var x in empNamenpn)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.PhoneNb + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Age")
{
dispfil.Clear();
foreach (var x in empNamena)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Age + Environment.NewLine;
}
}
else if (emsort.Text == "Name")
{
var empName = el.Select(i => new { i.ID, i.FullName }).OrderBy(x => x.FullName);
var empNamenAmp = el.Select(i => new { i.ID, i.FullName, i.Salary, i.Currency, i.Per }).OrderBy(x => x.FullName);
var empNamenAmpnwh = el.Select(i => new { i.ID, i.FullName, i.Salary, i.Currency, i.Per, i.Hours }).OrderBy(x => x.FullName);
var empNamenwh = el.Select(i => new { i.ID, i.FullName, i.Hours }).OrderBy(x => x.FullName);
var empNamenbd = el.Select(i => new { i.ID, i.FullName, i.Date }).OrderBy(x => x.FullName);
var empNamenad = el.Select(i => new { i.ID, i.FullName, i.Location }).OrderBy(x => x.FullName);
var empNamenpn = el.Select(i => new { i.ID, i.FullName, i.PhoneNb }).OrderBy(x => x.FullName);
var empNamena = el.Select(i => new { i.ID, i.FullName, i.Age }).OrderBy(x => x.FullName);
if (empfilcomb.Text == "Name")
{
dispfil.Clear();
foreach (var x in empName)
dispfil.Text += x.ID + ", " + x.FullName + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Amount paid")
{
dispfil.Clear();
foreach (var x in empNamenAmp)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Salary + " " + x.Currency + " " + x.Per + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Work Hours")
{
dispfil.Clear();
foreach (var x in empNamenwh)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Hours + Environment.NewLine;
}
else if (empfilcomb.Text == "Name,Amount paid and Work Hours")
{
dispfil.Clear();
foreach (var x in empNamenAmpnwh)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Salary + " " + x.Currency + " " + x.Per + ", " + x.Hours + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Birthday")
{
dispfil.Clear();
foreach (var x in empNamenbd)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Date + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Address")
{
dispfil.Clear();
foreach (var x in empNamenad)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Location + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Phone Number")
{
dispfil.Clear();
foreach (var x in empNamenpn)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.PhoneNb + Environment.NewLine;
}
else if (empfilcomb.Text == "Name and Age")
{
dispfil.Clear();
foreach (var x in empNamena)
dispfil.Text += x.ID + ", " + x.FullName + ", " + x.Age + Environment.NewLine;
}
}
and i was asking if there is a shorter way to do it:withing what i'm allowed to use. Seems that there isn't but thanks a lot for the help i'm sure what you guys provided is useful.

Can this LINQ be more efficient?

I have a fairly complex linq grouping with some repetition that annoys me, but I haven't been able to reduce it. Is there any way to avoid getting the list of items with ID=="XYZ" twice?
var example = = new GdsObservableCollection<GroupedQueryResults>(
items.Where(a => a.SubCategory3 != "{template}")
.GroupBy(item => item.SubCategory1)
.Select(g => new GroupedQueryResults
{
SubCategory = g.Key,
SectionHeader = (g.Count(x => x.Id == "XYZ") > 0) ?
"Category :" + g.Where(x => x.Id == "XYZ")
.First().NewValue :
"Item - " + itemNumber
...
The duplicate search for x.Id == "XYZ" can be avoided by using Where + Select + FirstOrDefault chain combined with C# null-coalescing operator:
SectionHeader = g
.Where(x => x.Id == "XYZ")
.Select(x => "Category :" + x.NewValue)
.FirstOrDefault() ?? "Item - " + itemNumber
I wouldn't say more efficient, but can be a little bit smaller, as you can use predicates inside Any and First:
var example = new GdsObservableCollection<GroupedQueryResults>(
items.Where(a => a.SubCategory3 != "{template}")
.GroupBy(item => item.SubCategory1)
.Select(g => new GroupedQueryResults
{
SubCategory = g.Key,
SectionHeader = g.Any(x => x.Id == "XYZ") ?
"Category :" + g.First(x => x.Id == "XYZ").NewValue :
"Item - " + itemNumber

Html Decode with Lambda Expression in .Net

I am trying to decode HTML in lambda expression but its giving following error:
"LINQ to Entities does not recognize the method 'System.String HtmlDecode(System.String)' method, and this method cannot be translated into a store expression."
And I am using code as bellow:
OtherUserInformation userData = db.Users
.Where(u => u.UserID.Equals(inputUserid))
.Select(x => new OtherUserInformation
{
Address = x.location == null ? "" : x.location,
UserPic = db.UserProfile
.Where(u => u.UserID.Equals(x.UserID))
.Select(y => y.profileImg)
.FirstOrDefault() == null
? profileImagePath + "140_profile_default.jpg"
: profileImagePath + "140_" + db.UserProfile
.Where(u => u.UserID.Equals(x.UserID))
.Select(y => y.profileImg)
.FirstOrDefault(),
CoverPic = db.UserProfile
.Where(u => u.UserID.Equals(x.UserID))
.Select(y => y.CoverImg)
.FirstOrDefault() == null
? coverImagePath + "812_cover_default.jpg"
: coverImagePath + coverPicPrefix + db.UserProfile
.Where(u => u.UserID.Equals(x.UserID))
.Select(y => y.CoverImg)
.FirstOrDefault(),
Detail = db.UserProfile
.Where(u => u.UserID.Equals(x.UserID))
.Select(y => y.About).FirstOrDefault() == null
? ""
: WebUtility.HtmlDecode(db.UserProfile
.Where(u => u.UserID.Equals(x.UserID))
.AsEnumerable()
.Select(y => y.About)
.FirstOrDefault()),
FollowerCount = db.FollowUser
.Where(u => u.FriendId.Equals(x.UserID) && u.FollowStatus.Equals(1))
.Count(),
Name = x.FirstName + " " + x.LastName,
IsFollow = db.FollowUser
.Where(u => u.UserId.Equals(userAuthInfo.UserId)
&& u.FriendId.Equals(inputUserid)
&& u.FollowStatus.Equals(1))
.Select(z => z)
.FirstOrDefault() == null ? "False" : "True",
})
.FirstOrDefault();
In above code, I need "Detail" field which have HTML encoded data. But I am not able to decode html in lambda expression.
Any help would be highly appreciate.
You can't use that method, or any like it, before you have resolved your query because sql doesn't know anything about that assembly. If it's not an EntityFunction then you have to reproject the list after resolution. If you use a data mapper like AutoMapper you can just use that in the reprojection and make the call there but if you need to do it by hand do it after you call toList().
db.Users.Select(x=>new YourObject{//data})
.ToList()
.Select(x=>new YourObject{
//now you can use whatever methods you want from whatever assemblies you want
SomePropertyValue = x.SomePropertyValue,
SomeOtherValue = SomeAssembly.SomeMethod(x.SomeOtherValue)
});
I got solution for this and added few line of code at the bottom of above query as bellow:
}).FirstOrDefault().AsEnumerable().Select(x => new OtherUserInformation
{
Address = x.Address,
UserPic = x.UserPic,
CoverPic = x.CoverPic,
Detail = Regex.Replace(x.Detail, "<.*?>", string.Empty),
FollowerCount = x.FollowerCount,
Name = x.Name,
IsFollow = x.IsFollow,
Categories = x.Categories,
Followers = x.Followers
}).FirstOrDefault();
Above solution worked for me. Happy coding :)
Try the HttpUtility.HtmlDecode Method instead
http://msdn.microsoft.com/en-us/library/system.web.httputility.htmldecode(v=vs.110).aspx
Or try the decoding the field inside the Select method as per the example below:
OtherUserInformation userData = db.Users.Where(u => u.UserID.Equals(inputUserid)).Select(x => new OtherUserInformation
{
Address = x.location == null ? "" : x.location,
// UserPic = Utilities.ImagePathForProfileForUserByDiviceType(db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).Select(y => y.profileImg).FirstOrDefault(),deviceType),
// CoverPic = Utilities.ImagePathForCoverImageForUserByDiviceType(db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).Select(y => y.CoverImg).FirstOrDefault(), deviceType),
UserPic = db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).Select(y => y.profileImg).FirstOrDefault() == null ? profileImagePath + "140_profile_default.jpg" : profileImagePath + "140_" + db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).Select(y => y.profileImg).FirstOrDefault(),
CoverPic = db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).Select(y => y.CoverImg).FirstOrDefault() == null ? coverImagePath + "812_cover_default.jpg" : coverImagePath + coverPicPrefix + db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).Select(y => y.CoverImg).FirstOrDefault(),
Detail = db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).Select(y => y.About).FirstOrDefault() == null ? "" : db.UserProfile.Where(u => u.UserID.Equals(x.UserID)).AsEnumerable().Select(y => WebUtility.HtmlDecode(y.About)).FirstOrDefault(),
FollowerCount = db.FollowUser.Where(u => u.FriendId.Equals(x.UserID) && u.FollowStatus.Equals(1)).Count(),
Name = x.FirstName + " " + x.LastName,
IsFollow = db.FollowUser.Where(u => u.UserId.Equals(userAuthInfo.UserId) && u.FriendId.Equals(inputUserid) && u.FollowStatus.Equals(1)).Select(z => z).FirstOrDefault() == null ? "False" : "True",
})
}).FirstOrDefault();

How do I specify "not in" in this lambda expression?

I have a quick question becuase my brain won't work with me...
Where do I specify that I want the user_id's in 'Users' that are NOT in 'Groups' ?
db.Users.Join(db.Groups, a => a.user_id, b => b.user_id, (a, b) => new SelectListItem
{
Value = a.user_id.ToString(),
Text = a.surname + " " + a.lastname
});
The following should work (assuming that I understood your question correctly):
db.Users
.Where(x => !db.Groups.Any(y => y.user_id == x.user_id))
.Select(a => new SelectListItem
{
Value = a.user_id.ToString(),
Text = a.surname + " " + a.lastname
});
you can try something like this:
var query = from u in db.Users
where !(from g in dc.Groups
select g.user_id)
.Contains(u.user_id)
select new SelectListItem {
Value = u.user_id.ToString(),
Text = u.surname + " " + u.lastname
};
Take a look here: http://introducinglinq.com/blogs/marcorusso/archive/2008/01/14/the-not-in-clause-in-linq-to-sql.aspx

Categories