Dynamic where clause using Linq expression having join with multiple tables - linq-to-sql

i have a linq query but in where clause is conditional. if eve.EventType is null then it will not include in where clause. How can we do with Linq lambda expression
var data= (from reg in product
join se in _order on reg.EventSessionId equals se.EventSessionId
join eve in Event on se.EventId equals eve.EventId
where eve.EventType == (EventType)eventType &&
((!string.IsNullOrEmpty(eve.EventName) && eve.EventName.Contains(SearchText, StringComparison.OrdinalIgnoreCase))
select (new OrderHistory
{
RegistrationId = reg.RegistrationId,
EventName = eve.EventName,
EventSesionName = se.EventSesionName,
})).ToList();
Thanks

This may help you.You should check null at first of your expression.
var data= (from reg in product
join se in _order on reg.EventSessionId equals se.EventSessionId
join eve in Event on se.EventId equals eve.EventId
where eve.EventType != null && eve.EventType == (EventType)eventType &&
((!string.IsNullOrEmpty(eve.EventName) && eve.EventName.Contains(SearchText, StringComparison.OrdinalIgnoreCase))
select (new OrderHistory
{
RegistrationId = reg.RegistrationId,
EventName = eve.EventName,
EventSesionName = se.EventSesionName,
})).ToList();

Related

How toPerform a left join in linq pad -

How can I get linq pad to run my left join as show below?
var query =
from s in db.CDBLogsHeaders
.OrderByDescending(g => g.LogDateTime)
from sc in db.StyleColors
.Where(stylecolor => stylecolor.id == (int?)s.StyleColorID)
.DefaultIfEmpty()
from c in db.StyleHeaders
.Where(styleHeader => styleHeader.id == (int?)s.StyleHeaderID)
.DefaultIfEmpty()
select new
{
CDBLogsHeaderId = s.Id,
Merchandiser = c.Merchandiser,
Material = s.Material,
Season = s.Season,
LogsHeaderLogType = s.LogType,
PushFromTo = s.PushFromTo,
LinePlan = s.LinePlan,
QuikRefNumber = s.QuikRefNumber,
PLMOrigin = s.PLM_Origin,
SeasonOriginal = c.SeasonOriginal,
SeasonCurrent = c.SeasonCurrent,
StyleHeaderId = c.Id,
StyleCode = c.StyleCode,
StyleColorsColorCode = sc.ColorCode
};
query.Dump();
The sql that linq pad creates runs perfectly in Management Studio but linq-pad doesn't display any rows and gives this error
InvalidOperationException: The null value cannot be assigned to a
member with type System.Int32 which is a non-nullable value type.
How can I get linqpad to work so I can play with it?
In your anonymous type, make sure your ints are returning ints.
Change
StyleHeaderId = c.Id,
To
StyleHeaderId = (c.Id == null ? 0 : c.Id),

LINQ Take syntax

I have written some LINQ to simulate an SQL GroupBy statement (see below). However, I also need to only consider only the last 10 settingIds before doing my group by. I think I would use Take to do this, but what would be the correct syntax in my statement?
var settings2 = from s in dc.SystemSettings
where s.campConfig.campaignType == campType
&& s.campId != campId
&& s.settingKey == ticket.setting.Key
orderby s.settingId descending
group s by s.settingValue
into grp
select new
{
SettingValue = grp.Key,
SettingCount = grp.Select(x => x.settingValue).Count()
};
I would do something like this
var settings2 = from sOuter in
(from s in dc.SystemSettings
where s.campConfig.campaignType == campType
&& s.campId != campId
&& s.settingKey == ticket.setting.Key
orderby s.settingId descending
select s).Take(10)
group sOuter by sOuter.settingValue
into grp
select new
{
SettingValue = grp.Key,
SettingCount = grp.Select(x => x.settingValue).Count()
};

"ERROR: Only one expression can be specified in the select list" Linq To Sql

var loggedInHours = db.LoginLogs.Where(l => l.UserId == u.Id && l.UserSessionStop != null)
.Sum(ls=> ls.UserSessionStart.Subtract(ls.UserSessionStop.Value).Hours)
I am trying to calculate Total LoggedIn Hours using this linq query..
But its giving me this error
"Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."
I don't know whats wrong with it..plz help
Try if this works:
var loggedInHours = db.LoginLogs.Where(l => l.UserId == u.Id && l.UserSessionStop != null)
.Select(l=> new {
StartTime = l.UserSessionStart,
EndTime = l.UserSessionStop
})
.ToList()
.Sum(c=> c.StartTime - c.EndTime);
btw, Is UserSessionStop nullable? If yes, then what will be the value to be subtracted?

Extremely slow join with join buffer

I am having a problem with a complex query with multiple joins. When running EXPLAIN:
Query
explain
select ud.id from user_detail ud
cross join ticket t
cross join guest_list gl
cross join event e
cross join venue v
where t.guest_list = gl.id and gl.event = e.id and e.venue = v.id
and (ud.account = 10 or ud.venue = 10 or ud.event = 10 or ud.guest_list = 10 or t.reference_user = 10 and (ud.guest_list=t.guest_list or ud.event = gl.event or ud.venue = e.venue or ud.account = v.account) and (t.guest_list = 10))
I get this:
id, select_type, table, type, rows, extra
1, SIMPLE, v, index, 2, "Using index"
1, SIMPLE, e, ref, 2, "Using where; using index"
1, SIMPLE, gl, ref, 1, "Using where; using index"
1, SIMPLE, t, ref, 418, "Using where"
1, SIMPLE, ud, ALL, 44028, "Using where; Using join buffer"
The data model is like this:
Account <1-> Venue <1-> Event <1-> GuestList <1-> Ticket
UserDetail has an account, venue, event or guest list as a parent.
And what I am trying to do with this query is to get all of the UserDetail that has one of the specific account/venue/event/guestlist as a parent, OR that has a guestlist as a parent that has a ticket that has the reference_user field set to a specific user.
Hibernate criteria
public List<UserDetail> listUserDetails(final Collection<UserDetailNode> anyOfNodes, final User orTicketReferenceUser, final Collection<GuestList> andAnyOfGuestlistsForTicketReferenceUser, final Collection<User> anyOfUsers, final Date fromLastModificationDate, final Date toLastModificationDate, final Boolean deletedNodes, final Boolean deletedUsers, final Boolean deletedUserDetails) {
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaQuery<UserDetail> cq = cb.createQuery(UserDetail.class);
final Root<UserDetail> userDetail = cq.from(UserDetail.class);
Predicate criteria = cb.conjunction();
if (anyOfNodes != null || orTicketReferenceUser != null) {
Predicate subCriteria = cb.disjunction();
if (anyOfNodes != null) {
Predicate anyOfNodesCriteria = cb.disjunction();
Collection<Account> anyOfAccounts = null;
Collection<Venue> anyOfVenues = null;
Collection<Event> anyOfEvents = null;
Collection<GuestList> anyOfGuestLists = null;
final Set<UserDetailNode> anyOfNodesWithParents = new HashSet<UserDetailNode>();
for (UserDetailNode node : anyOfNodes) {
while (node != null) {
anyOfNodesWithParents.add(node);
node = node.getParentNode();
}
}
for (final UserDetailNode node : anyOfNodesWithParents) {
if (node instanceof Account) {
if (anyOfAccounts == null) anyOfAccounts = new ArrayList<Account>();
anyOfAccounts.add((Account)node);
}
else if (node instanceof Venue) {
if (anyOfVenues == null) anyOfVenues = new ArrayList<Venue>();
anyOfVenues.add((Venue)node);
}
else if (node instanceof Event) {
if (anyOfEvents == null) anyOfEvents = new ArrayList<Event>();
anyOfEvents.add((Event)node);
}
else if (node instanceof GuestList) {
if (anyOfGuestLists == null) anyOfGuestLists = new ArrayList<GuestList>();
anyOfGuestLists.add((GuestList)node);
}
}
if (anyOfAccounts != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("account").in(anyOfAccounts)));
if (anyOfVenues != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("venue").in(anyOfVenues)));
if (anyOfEvents != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("event").in(anyOfEvents)));
if (anyOfGuestLists != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("guestList").in(anyOfGuestLists)));
subCriteria = cb.or(subCriteria, anyOfNodesCriteria);
}
if (orTicketReferenceUser != null && (andAnyOfGuestlistsForTicketReferenceUser == null || !andAnyOfGuestlistsForTicketReferenceUser.isEmpty())) {
final Root<Ticket> ticket = cq.from(Ticket.class);
Predicate ticketCriteria = cb.equal(ticket.get("referenceUser"), orTicketReferenceUser);
ticketCriteria = cb.and(ticketCriteria, cb.or(cb.equal(userDetail.get("guestList"), ticket.get("guestList")), cb.equal(userDetail.get("event"), ticket.get("guestList").get("event")), cb.equal(userDetail.get("venue"), ticket.get("guestList").get("event").get("venue")), cb.equal(userDetail.get("account"), ticket.get("guestList").get("event").get("venue").get("account"))));
if (andAnyOfGuestlistsForTicketReferenceUser != null) ticketCriteria = cb.and(ticketCriteria, ticket.get("guestList").in(andAnyOfGuestlistsForTicketReferenceUser));
subCriteria = cb.or(subCriteria, ticketCriteria);
}
criteria = cb.and(criteria, subCriteria);
}
if (anyOfUsers != null) {
if (anyOfUsers.isEmpty()) return new ArrayList<UserDetail>();
criteria = cb.and(criteria, userDetail.get("user").in(anyOfUsers));
}
if (fromLastModificationDate != null) criteria = cb.and(criteria, cb.greaterThanOrEqualTo(userDetail.<Date>get("lastModificationDate"), fromLastModificationDate));
if (toLastModificationDate != null) criteria = cb.and(criteria, cb.lessThanOrEqualTo(userDetail.<Date>get("lastModificationDate"), toLastModificationDate));
cq.select(userDetail).distinct(true).where(criteria);
return entityManager.createQuery(cq).getResultList();
}
From what I can see the last row is the problem, but how can I fix this? This query is auto-generated by hibernate, so I am not sure how much I can alter it.
Your over-use of cross-join Cartesian joins doesn't make sense... What is it you are actually looking for. Since your "OR" clauses are all based on this value of 10, but then doing an implicit join to the ticket table by the guest_list id -- and finally REQUIRING the t.guest_list = 10 ?
Since all your inner joins are ALSO looking at the original user detail table having same value as result of the join. Your kicker is that the FINAL "AND" is specifically looking for guest_list = 10. I would immediately start with this as the basis and OR the others... I might consider the following:
select STRAIGHT_JOIN
ud.id
from
ticket t
JOIN user_detail ud
ON t.guest_list = ud.guest_list
where
t.guest_list = 10
AND ( ud.account = 10
or ud.venue = 10
or ud.event = 10 )
You make a reference to a "Reference_User = 10", but what is that context... is that like one user detail has a guest? and that guest can be associated with the same user detail event/venue/account?
By providing some sample of the details, and clarification of what you are hoping to get will get you much further ahead...

LINQ to SQL Query Where Clause

I would like to create a single query that "adjusts" it's where clause based on a tuple. The first item in the tuple contains a enum value indicating the field in which to filter. The second tuple item is the filter value.
Notice the query below does not work:
var query = from p in db.Categories
where ( QueryBy.Item1 == CategoryFields.Name && p.Name == (string)(QueryBy.Item2) ) ||
( QueryBy.Item1 == CategoryFields.Id && p.Id == (long)(QueryBy.Item2) ) ||
( QueryBy.Item1 == CategoryFields.Description && p.Description == (string)(QueryBy.Item2) ) ||
( QueryBy.Item1 == CategoryFields.SortOrder && p.SortOrder == (int)(QueryBy.Item2) )
select...
if (query.Count() == 1) // ERRORS HERE CONVERSION OF INT
A similar query with only this where clause change will works:
var query = from p in db.Categories
where ( QueryBy.Item1 == CategoryFields.Name && p.Name == (string)(QueryBy.Item2) )
select...
if (query.Count() == 1) // Works HERE
Any idea what could be wrong? Can it be that LINQ where clause perform a short-circuit evaluation and thus the cast of item2 fails? Is there a better way to accomplish my overall goal of adjusting where clause?
Thanks in advance for your help!
LINQ to SQL isn't smart enough to optimize your query and generate it dynamically based on the value of your QueryBy.Item1. It will simply generate a SQL query let SQL server decide this for itself.
When you know that, the error makes sense, since it's impossible for one single value to be castable to both int, long, and string.
In your case you would be better of dynamically generating the right where clause. You can do this with the PredicateBuilder:
IQueryable<Category> query = db.Categories;
var whereClause = PredicateBuilder.False<Category>();
switch (QueryBy.Item1)
{
case CategoryFields.Name:
long id = (string)QueryBy.Item2;
whereClause = whereClause.Or(p => p.Name == name);
break;
case CategoryFields.Id:
string name = (string)QueryBy.Item2;
whereClause = whereClause.Or(p => p.Id == id);
break;
case CategoryFields.Description:
string des = (string)QueryBy.Item2;
whereClause =
whereClause.Or(p => p.Description == des);
break;
case CategoryFields.Id:
string sort = (int)QueryBy.Item2;
whereClause =
whereClause.Or(p => p.SortOrder == sort);
break;
}
query = query.Where(whereClause);