LINQ: Group By + Where in clause - linq

I'm trying to implement a T-SQL equivalent of a where in (select ...) code in LINQ.
This is what I have now:
int contactID = GetContactID();
IEnumerable<string> threadList = (from s in pdc.Messages
where s.ContactID == contactID
group 1 by new { s.ThreadID } into d
select new { ThreadID = d.Key.ThreadID}).ToList<string>();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group new { s } by new { s.ThreadID } into d
let maxMsgID = d.Where(x => x.s.ContactID != contactID).Max(x => x.s.MessageID)
select new {
LastMessage = d.Where(x => x.s.MessageID == maxMsgID).SingleOrDefault().s
};
However, my code won't compile due to this error for the ToList():
cannot convert from
'System.Linq.IQueryable<AnonymousType#1>'
to
'System.Collections.Generic.IEnumerable<string>'
Anyone have any suggestions on how to implement this? Or any suggestions on how to simplify this code?

Your query returns a set of anonymous types; you cannot implicitly convert it to a List<string>.
Instead, you should select the string itself. You don't need any anonymous types.
Change it to
var threadList = pdc.Messages.Where(s => s.ContactID == contactID)
.Select(s => s.ThreadID)
.Distinct()
.ToList();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group s by s.ThreadID into d
let maxMsgID = d.Where(x => x.ContactID != contactID).Max(x => x.MessageID)
select new {
LastMessage = d.Where(x => x.MessageID == maxMsgID).SingleOrDefault()
};

Related

Convert if and foreach statement to select and where in linq

How would I go about changing my if statement and foreach to something cleaner in linq using select and where.
I've tried to make the if statement into a where clause and then use the select query as a replacement for the Foreach loop but that seem to have type issues and wasn't working.
{
StripeConfiguration.ApiKey = _appSettings.StripeSecretKey;
var profile = await _userManager.FindByIdAsync(customerServiceID);
var stripeId = profile.StripeAccountId;
if (stripeId == null)
throw new ArgumentException("No associated Stripe account found.");
List<PaymentMethodDto> result = new List<PaymentMethodDto>();
var options = new PaymentMethodListOptions
{
Customer = stripeId,
Type = "card",
};
var service = new PaymentMethodService();
var payments = await service.ListAsync(options);
if (payments != null && payments.Data?.Count > 0)
{
payments.Data.ForEach((x) =>
{
result.Add(
new PaymentMethodDto
{
Brand = x.Card.Brand,
LastDigits = x.Card.Last4,
StripeToken = x.Id,
CustomerID = x.CustomerId
});
});
}
return result;
}
Just do a regular Select.
List<PaymentMethodDto> result = payments.Data.Select(x => new PaymentMethodDto
{
Brand = x.Card.Brand,
LastDigits = x.Card.Last4,
StripeToken = x.Id,
CustomerID = x.CustomerId
})
.ToList();
If payments.Data has nothing in it, this will give you an empty list, which is what you want.
If payments is null, you'll get an exception, which I think if you think about it really hard is probably what you really want in that case too. Why would .ListAsync() yield a null value?

Unable to cast object of type 'System.Collections.Generic.HashSet`1[libraryWebProject.Major]' to type 'libraryWebProject.Major'

I have this code in the code behind file
LibraryArticlesEntities la = new LibraryArticlesEntities();
int id = 17;
if (Request.QueryString["TitleID"] != null)
{
id = Int32.Parse(Request.QueryString["TitleID"]);
}
var gettitle = la.Titles.Where(t => t.ID == id).Select(t => t.Title1);
header.InnerHtml += gettitle;
var sub = la.Titles.Where(t => t.ID == id).Select(t => t.Majors);
foreach (Major major in sub) // the error is here
{
subject.InnerHtml += major.MajorName + " ";
}
Here I'm using a LINQ query to fetch a list of majors but I get this error when I try to iterate over it and display their names:
Unable to cast object of type 'System.Collections.Generic.HashSet`1[libraryWebProject.Major]' to type 'libraryWebProject.Major'.
The relationship between Title and Major is many to many and I have an association table linking Title ID and Major ID
Please try to make sub a List<Major> by adding .ToList(); at the end of your select.
var sub = la.Titles.Where(t => t.ID > 0)
.SelectMany(a => a.Majors.Select(b=>b)).ToList();
This line:
var sub = la.Titles.Where(t => t.ID == id).Select(t => t.Majors);
and the fact that "The relationship between Title and Major is many to many"
implies that the result of the Select is a collection of collections, so your loop will have to be:
foreach (var listOfMajors in sub)
{
foreach (var major in listOfMajors)
{
// Do stuff
}
}
Old answer replaced after it was revealed that the question didn't actually include the code that was in error.
Please try with ToList() and use var in foreach:
var sub = la.Titles.Where(t => t.ID == id)
.Include(t => t.Majors)
.Select(t => t.Majors).ToList();//use tolist() here
foreach (var major in sub) // and add var here please
{
subject.InnerHtml += major.MajorName + " ";
}

Conversion of a LINQ query fom method syntax to query syntax

Hi I am changing career to computer programming. I am still in college. I have to change the following LINQ query from method syntax to query syntax. What gets me is the 2 steps process of the method query. First it gets a teamId and then it returns a list based on the context and using the teamId. I am confused about how to translate this to query method. Most of the questions are about going from query syntax to method.
Can someone Help?
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = context
.TeamMembers
.Include("Team")
.FirstOrDefault(c => c.UserId == userId)
.Team.Id;
return context
.TeamTemplates.Include("Template")
.Where(c => c.TeamId == teamId)
.Select(c => c.Template)
.Where(c => c.StatusId == 1/*Active*/)
.Select(k => new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
}
}
The first one is pretty straight forward. I delayed the execution of the query until the end. Since you may get a null reference exception in your example accessing .FirstOrDefault().Team.Id;
var teamId = (from c in context.TeamMembers.Include("Team")
where c.UserId == userId
select c.Team.Id).FirstOrDefault();
This one you just need to use an into in order to continue your query statement
return (from c in context.TeamTemplates.Include("Template")
where c.TeamId == teamId
select c.Template into k
where k.StatusId == 1
select new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = (from tm in context.TeamMembers.Include("Team")
where tm.UserId==userId
select tm.Id).FirstOrDefault();
IEnumerable<TemplateView> result = from k in (from tmp in context.TeamTemplates.Include("Template")
select tmp.Template)
where k.StatusId==1
select new
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
};
return result;
}

Return the result of joining two tables in Silverlight 4.0

Main Code:
DomainServiceAccountManager d = new DomainServiceAccountManager();
EntityQuery<ListBuy> q = d.GetListMemberBuyQuery();
LoadOperation<ListBuy> l = d.Load(q);
DGListBuy.ItemsSource = l.Entities;
The code:
public IQueryable<ListBuy> GetListMemberBuy()
{
var membuy =
from mem in this.ObjectContext.Members
from b in this.ObjectContext.Buys.Where(b => b.ID_member == mem.ID)
.OrderByDescending(b => b.ID)
.DefaultIfEmpty()
select new { b.ID, mem.Name, b.Money, b.Tarikh };
return membuy;
}
I get the following message:
Cannot implicitly convert type 'System.Linq.IQueryable<AnonymousType#1>' to 'System.Linq.IQueryable<AccountManager.Web.ListBuy>'. An explicit conversion exists (are you missing a cast?)
You method GetListMemberBuy actually returns an IQueryable of anonymous type instead of an IQueryable of type ListBuy. These are not identical, hence the (compile time?) error.
I can only assume that ListBuy also exists in the database, but if so, then you can remove the anonymous type.
public IQueryable<ListBuy> GetListMemberBuy()
{
var membuy =
from mem in this.ObjectContext.Members
from b in this.ObjectContext.Buys.Where(b => b.ID_member == mem.ID)
.OrderByDescending(b => b.ID)
.DefaultIfEmpty()
select new ListBuy() { ID = b.ID, Name = mem.Name, Money = b.Money, Tarikh = b.Tarikh }; // <-- new ListBuy() !!
return membuy;
}
If ListBuy does not exist in the database, then you cannot return an IQueryable. Maybe this will work.
public IEnumerable<ListBuy> GetListMemberBuy()
{
var membuy =
from mem in this.ObjectContext.Members
from b in this.ObjectContext.Buys.Where(b => b.ID_member == mem.ID)
.OrderByDescending(b => b.ID)
.DefaultIfEmpty()
select new { b.ID, mem.Name, b.Money, b.Tarikh };
return membuy
.AsEnumerable()
.Select(b => new ListBuy() {
ID = b.ID, Name = b.Name, Money = b.Money, Tarikh = b.Tarikh
});
}
All this is a bit speculation since you didn't include the ListBuy class definition in your question.

Linq: Nested queries are better than joins, but what if you use 2 nested queries?

In her book Entity Framework Julie Lerman recommends using nested queries in preference to joins (scroll back a couple of pages).
In her example see populates 1 field this way, but what id you want to populate 2?
I have an example here where I would prefer to populate the Forename and Surname with the same nested query rather than 2 separate ones. I just need to know the correct syntax to do this.
public static List<RequestInfo> GetRequests(int _employeeId)
{
using (SHPContainerEntities db = new SHPContainerEntities())
{
return db.AnnualLeaveBookeds
.Where(x => x.NextApproverId == _employeeId ||
(x.ApproverId == _employeeId && x.ApprovalDate.HasValue == false))
.Select(y => new RequestInfo
{
AnnualLeaveDate = y.AnnualLeaveDate,
Forename = (
from e in db.Employees
where e.EmployeeId == y.EmployeeId
select e.Forename).FirstOrDefault(),
Surname = (
from e in db.Employees
where e.EmployeeId == y.EmployeeId
select e.Surname).FirstOrDefault(),
RequestDate = y.RequestDate,
CancelRequestDate = y.CancelRequestDate,
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty
})
.OrderBy(x => x.AnnualLeaveDate)
.ToList();
}
}
There's nothing wrong with your query, but you can write it in a way that is much simpler, without the nested queries:
public static List<RequestInfo> GetRequests(int employeeId)
{
using (SHPContainerEntities db = new SHPContainerEntities())
{
return (
from x in db.AnnualLeaveBookeds
where x.NextApproverId == employeeId ||
(x.ApproverId == employeeId && x.ApprovalDate == null)
orderby x.AnnualLeaveDate
select new RequestInfo
{
AnnualLeaveDate = x.AnnualLeaveDate,
Forename = x.Employee.Forename,
Surname = x.Employee.Surname,
RequestDate = x.RequestDate,
CancelRequestDate = x.CancelRequestDate,
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty
}).ToList();
}
}
See how I just removed your from e in db.Employees where ... select e.Forename) and simply replaced it with x.Employee.Forename. When your database contains the correct foreign key relationships, the EF designer will successfully generate a model that contain an Employee property on the AnnualLeaveBooked entity. Writing the query like this makes it much more readable.
I hope this helps.
try this
using (SHPContainerEntities db = new SHPContainerEntities())
{
return db.AnnualLeaveBookeds
.Where(x => x.NextApproverId == _employeeId ||
(x.ApproverId == _employeeId && x.ApprovalDate.HasValue == false))
.Select(y =>
{
var emp = db.Emplyees.Where(e => e.EmployeeId == y.EmployeeId);
return new RequestInfo
{
AnnualLeaveDate = y.AnnualLeaveDate,
Forename = emp.Forename,
Surname = emp.Surname,
RequestDate = y.RequestDate,
CancelRequestDate = y.CancelRequestDate,
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty
};
).OrderBy(x => x.AnnualLeaveDate).ToList();
}

Resources