how to pass string variable to linq select new {} section - linq

Ii just want to make search functionality with linq with multiple ColumnNames that stored to session variable. I'm using one method:
public void FillGrid(string CommandName,string ColumnName, string SearchText)
That has three string variable that stores session value.
Now I just want to pass ColumnName with this query:
var query1 = (from p in db.Posts
join c in db.Categories on p.Category_id equals c.Id
join u in db.Users on p.User_id equals u.Id
where (p.ToUser_id == user_id || p.ToUser_id == null) && p.User_id != user_id
orderby p.Sent_Datetime descending
select new
{
Id = p.Id,
Title = p.Title,
Publisher = u.First_name + " " + u.Last_name,
ToUser = p.ToUser_id,
PublishDate = p.Sent_Datetime,
IsFile = p.IsFileAttached,
CategoryName = c.Category_name,
status_name = (from s in db.Status where (s.Id == p.status_id) select s.status_name).FirstOrDefault(),
Group_name = (from g in db.Groups where (g.Id == p.group_id) select g.Group_name).FirstOrDefault(),
FileSize = p.TotalFileSize,
ColumnName = Sesssion["ColumnName"].ToString()
}).Where(q => q.ColumnName.Contains(SearchText));
However, ColumnName does not give any text or it may be not part of this query i have to manually give column name because.
for multiple column i have, so i can not use this statement like:
.Where(q => q.Tile.Contains(SearchText));
this query works fine with single column. but there is multiple column i have so i have to set q.ColumnName from outer side.

I would do an extension method for that kind of things, building an expression for your predicate.
public static class Helper
{
public static IQueryable<T> FilterForColumn<T>(this IQueryable<T> queryable, string colName, string searchText)
{
if (colName != null && searchText != null)
{
var parameter = Expression.Parameter(typeof(T), "m");
var propertyExpression = Expression.Property(parameter, colName);
var searchExpression = Expression.Constant(searchText);
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var body = Expression.Call(propertyExpression, containsMethod, searchExpression);
var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });
return queryable.Where(predicate);
}
else
{
return queryable;
}
}
}
usage in your case
var query1 = (from p in db.Posts
join c in db.Categories on p.Category_id equals c.Id
join u in db.Users on p.User_id equals u.Id
where (p.ToUser_id == user_id || p.ToUser_id == null) && p.User_id != user_id
orderby p.Sent_Datetime descending
select new
{
Id = p.Id,
Title = p.Title,
Publisher = u.First_name + " " + u.Last_name,
ToUser = p.ToUser_id,
PublishDate = p.Sent_Datetime,
IsFile = p.IsFileAttached,
CategoryName = c.Category_name,
status_name = (from s in db.Status where (s.Id == p.status_id) select s.status_name).FirstOrDefault(),
Group_name = (from g in db.Groups where (g.Id == p.group_id) select g.Group_name).FirstOrDefault(),
FileSize = p.TotalFileSize,
}).FilterForColumn(Sesssion["ColumnName"].ToString(), SearchText);

Related

How to return FirstOrDefaultAsync EF Linq to entity List query

I have this Linq to entity query that returns a list of visitors with joins.
I want a similar query to return a single record without the query being a List collection, but changing it to a basic select with FirstOrDefaultAsync gets the error "A query body must end with a select clause or a group clause"
public async Task<List<VisitorDetail>> GetOneVisitor(int visitorId)
{
var query = await (from v in _context.Visitors
where v.Id == visitorId
join d in _context.Categories on v.VisitCategoryId equals d.Id
join c in _context.Counters on v.AssignedCounter equals c.Host into counterGroup
from cg in counterGroup.DefaultIfEmpty()
select new
{
FirstName = v.FirstName,
LastName = v.LastName,
CounterDescription = cg.Description,
VisitCategory = d.Description
}).ToListAsync();
List<VisitorDetail> visitors = new();
foreach (var p in query)
{
visitors.Add(new VisitorDetail
{
FirstName = p.FirstName,
LastName = p.LastName,
CounterDescription = p.CounterDescription,
CategoryDescription = p.VisitCategory
});
}
return visitors;
}
If you want to keep DRY with LINQ to Entities, return IQueryable for your common queries and invoke materialization only when it is needed.
Your method can be rewritten in the following way:
public IQueryable<VisitorDetail> GetVisitorDetails(int visitorId)
{
var query =
from v in _context.Visitors
where v.Id == visitorId
join d in _context.Categories on v.VisitCategoryId equals d.Id
join c in _context.Counters on v.AssignedCounter equals c.Host into counterGroup
from cg in counterGroup.DefaultIfEmpty()
select new VisitorDetail
{
FirstName = v.FirstName,
LastName = v.LastName,
CounterDescription = cg.Description,
CategoryDescription = d.Description
};
return query;
}
var many = await GetVisitorDetails(visitorId).ToListAsync();
var one = await GetVisitorDetails(visitorId).FirstOrDefaultAsync();

i am trying to join 3 tables below is the code

var result = (from p in db.push_notifications
join nu in db.notification_recievers on p.id equals nu.push_notification_id
join nt in db.notification_types on p.notification_type_id equals nt.id
where (p.id == pushNotificationId && p.send_criteria == criteria && nu.delete_flag == false && p.delete_flag == false && nt.delete_flag == false)
select new NotificationList
{
conferenceId = p.conference_id,
pushNotificationId = p.id,
notificationId = nt.id,
notificationType = nt.notification_type,
nottificationDate = p.created_dt_tm,
criteria = (int)p.send_criteria,
notificationMessage = p.notification_msg,
userEmail=null,
userInterests = **getInterestNamesByPushNotificationId(p.id)**,
userEvents=null
}).Distinct();
public string getInterestNamesByPushNotificationId(int id)
{
string interests = string.Empty;
var query = from i in db.interests
join pn in db.notification_recievers
on i.id equals pn.interest_id
where pn.push_notification_id == id && pn.delete_flag == false
select new
{
name = i.name
};
foreach (var intr in query.Distinct())
{
if (interests == "")
{
interests = intr.name;
}
else
{
interests = interests + ", " + intr.name;
}
}
return interests;
}
this is throwing me error
LINQ to Entities does not recognize the method 'System.String
getInterestNamesBy PushNotification(Int32)' method, and this method
cannot be translated into a store expression.
The Entity Framework is trying to execute your LINQ clause on the SQL side, obviously there is no equivalent to 'getInterestNamesBy PushNotification(Int32)' from a SQL perspective.
You need to force your select to an Enumerable and then reselect your object using the desired method.
Not ideal but something like this should work - (not tested this so be nice).
var result = (from p in db.push_notifications
join nu in db.notification_recievers on p.id equals nu.push_notification_id
join nt in db.notification_types on p.notification_type_id equals nt.id
where (p.id == pushNotificationId && p.send_criteria == criteria && nu.delete_flag == false && p.delete_flag == false && nt.delete_flag == false)
select new { p=p, nu = nu, nt = nt }).AsEnumerable().Select( x => new NotificationList()
{
conferenceId = x.p.conference_id,
pushNotificationId = x.p.id,
notificationId = x.nt.id,
notificationType = x.nt.notification_type,
nottificationDate = x.p.created_dt_tm,
criteria = (int)x.p.send_criteria,
notificationMessage = x.p.notification_msg,
userEmail=null,
userInterests = getInterestNamesByPushNotificationId(x.p.id),
userEvents=null
}).Distinct();
i have done it this way
In my model
using (NotificationService nService = new NotificationService())
{
modelView = nService.DetailsOfNotifications(pushNotificationId, criteriaId).Select(x => new NotificationViewModelUI(x.conferenceId, x.pushNotificationId, x.notificationId, x.notificationType, x.nottificationDate, x.criteria, x.notificationMessage, x.userEmail, nService.getInterestNamesByPushNotificationId(x.pushNotificationId), nService.getIEventTitlesByPushNotificationId(x.pushNotificationId))).ToList();
}
public NotificationViewModelUI(int conferenceId, int pushNotificationId, int notificationId, string notificationType, DateTime dateTime, int criteria, string nMessage, string emailId = null, string interestNames = null, string eventTitles = null)
{
this.conferenceId = conferenceId;
this.pushNotificationId = pushNotificationId;
this.notificationId = notificationId;
this.notificationType = notificationType;
this.notificationDate = dateTime;
this.sendCriteria = (NotificationCriteria)criteria;
this.notificationMessage = nMessage;
this.emailId = NotificationCriteria.SpecificUser.Description() +"... "+ emailId;
this.interestNames = NotificationCriteria.UserByInterests.Description() + "... " + interestNames;
this.eventTitles = NotificationCriteria.UserByEvents.Description() + "... " + eventTitles;
}

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;
}

LINQ join issue, returns all null value

I am new in EF and LINQ and I am facing a strange issue. When I check null value in my select new block, all values from child table is coming null. Below is the LINQ query.
My Linq Code
var linqResult = from pd in entities.tblpackagedetails
join ps in entities.tblpackageselecteds
on pd.PackageDetailsID equals ps.PackageDetailsID
into tabJoin
from tj in tabJoin.Where(ps => ps.UserID == userID
&& ps.IsActive == true).DefaultIfEmpty()
select new
{
IsComplete = (tj == null) ? false : tj.IsComplete,
IsActive = (tj == null) ? false : tj.IsActive,
UserID = (tj == null) ? 0 : tj.UserID,
IsMandatory = pd.IsMandatory,
PackageSelectedID = (tj == null) ? 0 : tj.PackageSelectedID,
IsSelected = (tj == null ? false : tj.IsSelected),
pd.Amount,
pd.Code,
pd.Description,
pd.Points,
pd.PackageDetailsID
};
foreach (var result in linqResult)
{
packagesSelected.Add(new PackageDetailDataModel()
{
Amount = result.Amount,
Code = result.Code,
Description = result.Description,
IsComplete = result.IsComplete,
IsMandatory = result.IsMandatory,
PackageDetailsID = result.PackageDetailsID,
PackageSelectedID = result.PackageSelectedID,
Points = result.Points,
IsActive = result.IsActive,
UserID = result.UserID,
IsSelected = result.IsSelected
});
}
SQL generated by Visualizer
SELECT
`Extent1`.`PackageDetailsID`,
`Extent2`.`IsComplete`,
`Extent2`.`IsActive`,
`Extent2`.`UserID`,
`Extent1`.`IsMandatory`,
`Extent2`.`PackageSelectedID`,
`Extent2`.`IsSelected`,
`Extent1`.`Amount`,
`Extent1`.`Code`,
`Extent1`.`Description`,
`Extent1`.`Points`
FROM `tblpackagedetails` AS `Extent1`
LEFT OUTER JOIN `tblpackageselected` AS `Extent2`
ON (`Extent1`.`PackageDetailsID` = `Extent2`.`PackageDetailsID`)
AND ((`Extent2`.`UserID` = #linq_0) AND (1 = `Extent2`.`IsActive`))
When I ran above sql in MySQL workbench I got below output (repalcing #linq_0 with userID).
My Parent Table Structure
Child Table Structure
Output I want
But the values for IsComplete, IsActive, UserID, PackageSelectedID and IsSelected null as a result condition checking in select new block assign false or 0.
If I remove null checking, I get value for first 3 rows and in fourth iteration I get below exception.
The cast to value type 'Boolean' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type
Please help... :(
Working code block
packagesSelected = new List<PackageDetailDataModel>();
var linqResult = from pd in entities.tblpackagedetails
join ps in entities.tblpackageselecteds
on pd.PackageDetailsID equals ps.PackageDetailsID
into tabJoin
from tj in tabJoin.Where(ps => ps.UserID == userID
&& ps.IsActive == true).DefaultIfEmpty()
select new
{
IsComplete = (bool?)tj.IsComplete,
IsActive = (bool?)tj.IsActive,
UserID = (int?)tj.UserID,
IsMandatory = pd.IsMandatory,
PackageSelectedID = (int?)tj.PackageSelectedID,
IsSelected = (bool?)tj.IsSelected,
pd.Amount,
pd.Code,
pd.Description,
pd.Points,
pd.PackageDetailsID
};
foreach (var result in linqResult)
{
packagesSelected.Add(new PackageDetailDataModel()
{
Amount = result.Amount,
Code = result.Code,
Description = result.Description,
IsComplete = (result.IsComplete ?? false),
IsMandatory = result.IsMandatory,
PackageDetailsID = result.PackageDetailsID,
PackageSelectedID = (result.PackageSelectedID ?? 0),
Points = result.Points,
IsActive = (result.IsActive ?? false),
UserID = (result.UserID ?? 0),
IsSelected = (result.IsSelected ?? false)
});
}
Thanks to 2Kay :)
When tj is null, EF consieders all properties of tj as null. It's ok, but when EF trying to materialize them into value-types it fails. So the solution is to use nullable types..
Try this query:
var linqResult = from pd in entities.tblpackagedetails
join ps in entities.tblpackageselecteds
on pd.PackageDetailsID equals ps.PackageDetailsID
into tabJoin
from tj in tabJoin.Where(ps => ps.UserID == userID
&& ps.IsActive == true).DefaultIfEmpty()
select new
{
IsComplete = (bool?) tj.IsComplete,
IsActive = (bool?) tj.IsActive,
UserID = (int?) tj.UserID,
IsMandatory = pd.IsMandatory,
PackageSelectedID = (int?) tj.PackageSelectedID,
IsSelected = (bool?) tj.IsSelected,
pd.Amount,
pd.Code,
pd.Description,
pd.Points,
pd.PackageDetailsID
};

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