in Linq replace null to empty - c#

var ch = _context.xxtu_nintex_emp_data_v
.Where(o => o.LOGIN_USER_NAME ==userId.ToUpper())
.Select(emp => new
{ OTHERMOBILENO = emp.OTHERMOBILENO ?? "" })
.ToList().SingleOrDefault();
the result is
when use toList() I get what I want but it is so slow
var ch = _context.xxtu_nintex_emp_data_v.ToList()
.Where(o => o.LOGIN_USER_NAME ==userId.ToUpper())
.Select(emp => new
{ OTHERMOBILENO = emp.OTHERMOBILENO ?? "" })
.ToList().SingleOrDefault();
the result is
I use code first approach api and Microsoft.EntityFrameworkCore

Some things you could try
Call ToList after the condition, to only fetch a subset of data from the Database
var ch = _context.xxtu_nintex_emp_data_v
.Where(o => o.LOGIN_USER_NAME == userId.ToUpper())
.ToList() //<-- here
.Select(emp => new
{ OTHERMOBILENO = emp.OTHERMOBILENO ?? "" })
.ToList().SingleOrDefault();
Move the Select after the Last ToList call
var ch = _context.xxtu_nintex_emp_data_v
.Where(o => o.LOGIN_USER_NAME == userId.ToUpper())
//<-- re-arrange ToList/Select
.ToList()
.Select(emp => new { OTHERMOBILENO = emp.OTHERMOBILENO ?? "" })
//<--
.SingleOrDefault();
Re-arrange it a bit more
var emp = _context.xxtu_nintex_emp_data_v
.Where(o => o.LOGIN_USER_NAME == userId.ToUpper())
.SingleOrDefault();
var ch = new { OTHERMOBILENO = emp?.OTHERMOBILENO ?? "" };

Related

Select multiple child columns with the same filter

I have this Linq lambda expression which generates abnormally complex SQL select to database. Is it somehow possibility to simplify it?
var devices = db.Devices
.Where(a => a.active == true)
.Select(a => new DeviceToDisplay
{
Id = a.Id,
serialNumber = a.serialNumber,
deviceRegion = a.deviceRegion,
activeIP = a.IPaddresses.Where(b => b.active == true).Select(b => b.IPaddress1).FirstOrDefault(),
Wip = a.IPaddresses.Where(b => b.active == true).Select(b => b.W_IP).FirstOrDefault(),
Sip = a.IPaddresses.Where(b => b.active == true).Select(b => b.S_IP).FirstOrDefault(),
model = a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).Select(c => c.model).FirstOrDefault(),
firmware = a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).Select(c => c.firmware).FirstOrDefault(),
lastMPteamActivity = a.activityLogs.OrderByDescending(c => c.updatedDate).Select(c => c.updatedDate).FirstOrDefault(),
country = a.MPPinformations.Select(c => c.country).FirstOrDefault()
});
For a start, your linq query looks very complicated. Imagine how you would implement this by writing a SQL query for example.
A suggestion: you are writing things like:
a.IPaddresses.Where(b => b.active == true).
and
a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).
in multiple places.
Instead you could create an anonymous type. For example,
var foo = from x in sb.Devices.Where(a=> a.active)
select new { Id = x.ID,
IPAddress = a.IPaddresses.Where(b => b.active), ... }
You can then use foo to create your Devices object.
See if this is any better:
var devices = db.Devices
.Where(a => a.active == true)
.Select(a => new DeviceToDisplay {
Id = a.Id,
serialNumber = a.serialNumber,
deviceRegion = a.deviceRegion,
activeIP = a.IPaddresses.Where(b => b.active == true).FirstOrDefault(),
SPdata = a.SPdatas.Where(c => c.model != "").OrderByDescending(c => c.collectionDate).FirstOrDefault(),
lastMPteamActivity = a.activityLogs.OrderByDescending(c => c.updatedDate).Select(c => c.updatedDate).FirstOrDefault(),
country = a.MPPinformations.Select(c => c.country).FirstOrDefault()
})
.Select(a=> new DeviceToDisplay {
Id=a.Id,
serialNumber=a.serialNumber,
deviceRegion=a.deviceRegion,
activeIP=a.activeIP.IPaddress1,
Wip=a.activeIP.W_IP,
Sip=a.activeIP.S_IP,
model=a.SPdata.model,
firmware=a.SPdata.firmware,
lastMPteamActivity=a.lastMPteamActivity,
country=a.county
});

The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities

var residenceRep =
ctx.ShiftEmployees
.Include(s => s.UserData.NAME)
.Include(s => s.ResidenceShift.shiftName)
.Join(ctx.calc,
sh => new { sh.empNum, sh.dayDate },
o => new { empNum = o.emp_num, dayDate = o.trans_date },
(sh, o) => new { sh, o })
.Where(s => s.sh.recordId == recordId && s.o.day_flag.Contains("R1"))
.OrderBy(r => r.sh.dayDate)
.Select(r => new
{
dayDate = r.sh.dayDate,
empNum = r.sh.empNum,
empName = r.sh.UserData.NAME,
shiftId = r.sh.shiftId,
shiftName = r.sh.ResidenceShift.shiftName,
recordId,
dayState = r.o.day_desc.Split('[', ']')[1]
}).ToList();
I get an exception :
The LINQ expression node type 'ArrayIndex' is not supported in LINQ to
Entities
How i could find an alternative to Split('[', ']')[1] in this query
You must commit the query and do the split after loading the data:
var residenceRep =
ctx.ShiftEmployees
.Include(s => s.UserData.NAME)
.Include(s => s.ResidenceShift.shiftName)
.Join(ctx.calc,
sh => new { sh.empNum, sh.dayDate },
o => new { empNum = o.emp_num, dayDate = o.trans_date },
(sh, o) => new { sh, o })
.Where(s => s.sh.recordId == recordId && s.o.day_flag.Contains("R1"))
.OrderBy(r => r.sh.dayDate)
.Select(r => new
{
dayDate = r.sh.dayDate,
empNum = r.sh.empNum,
empName = r.sh.UserData.NAME,
shiftId = r.sh.shiftId,
shiftName = r.sh.ResidenceShift.shiftName,
recordId = r.sh.recordId,
dayState = r.o.day_desc,
})
.ToList()//Here we commit the query and load data
.Select(x=> {
var parts = x.dayState.Split('[', ']');
return new {
x.dayDate,
x.empNum,
x.empName,
x.shiftId,
x.shiftName,
x.recordId,
dayState = parts.Length > 1 ?parts[1]:"",
};
})
.ToList();
I had this Issue and the approach that I've chose was that get all element I wanted and save them into a List and then filter the actual data on that list.
I know this is not the best answer but it worked for me.

C# - LINQ to Entity query attaching the value of the properties to one variable

I have this query:
var sole = SoleService.All().Where(c => c.Status != 250)
.Select(x => new {
ID = x.ID, Code = new {CodeName = x.Code + x.Country},
Name = x.Name
})
.Distinct()
.OrderBy(s => s.Code);
Like this it gives me an error. What I want is to combine Code and Country like concat strings so I can use the new variable for my datasource. Something like - 001France
P.S
What I am using and is working right now is this :
var sole = SoleService.All().Where(c => c.Status != 250)
.Select(x => new {
ID = x.ID, Code = x.Code, Name = x.Name, Country = x.Country })
.Distinct()
.OrderBy(s => s.Code);
So what I need is to modify this query so I can use Code +Country as one variable. Above is just my try that I thought would work.
Sound like:
var sole = SoleService.All().Where(c => c.Status != 250)
.AsEnumerable()
.Select(x => new {
ID = x.ID,
Code = x.Code + x.Country,
Name = x.Name
})
.Distinct()
.OrderBy(s => s.Code);
You don't need inner anonymous type at all. If you are working on EF, sine string + is not supported, call AsEnumerable before doing select.
You can't sort by s.Code because it's an instance of an anonymous type. I'd go with
var sole = SoleService.All().Where(c => c.Status != 250)
.Select(x => new { ID = x.ID, Code = new {CodeName = x.Code + x.Country}, Name = x.Name })
.Distinct()
.OrderBy(s => s.Code.CodeName);
Try to add .toString() because the problem should be the + operator believe you try to add numeric properties...
Like that :
var sole = SoleService.All().Where(c => c.Status != 250)
.Select(x => new { ID = x.ID, Code = new {CodeName = x.Code.ToString() + x.Country.ToString()}, Name = x.Name })
.Distinct()
.OrderBy(s => s.Code);

Add correlated subqueries to Select statement using QueryOver

I'm attempting to convert a SQL statement to use QueryOver (in hopes of pre-fetching the entities part of the response) but I'm having trouble figuring out how to add a correlated subquery to the Select statement (all the examples I found have only shown using a subquery in the Where clause).
This is the query I'm trying to convert:
var pendingFeedbackStatus = Session.QueryOver<FeedbackStatus>().Where(fs => fs.Name == "pending");
var projectWhereClause = project != null ? "AND f1.project_id = " + project.Id : "";
var query = Session.CreateSQLQuery(string.Format(#"
SELECT
ft.id as FEEDBACK_TYPE_ID,
(SELECT COUNT(*) FROM FEEDBACK f1 WHERE ft.id = f1.feedback_type_id AND f1.archive_ind = 0 {0}) as ALL_FEEDBACK_COUNT,
(SELECT COUNT(*) FROM FEEDBACK f1 WHERE ft.id = f1.feedback_type_id AND f1.archive_ind = 0 {0} AND feedback_status_id = {1}) as PENDING_FEEDBACK_COUNT
FROM feedback f
RIGHT JOIN feedback_type ft on f.feedback_type_id = ft.id WHERE ft.RESTRICTED_IND = 0
GROUP BY ft.id, ft.sort_order
ORDER BY ft.sort_order",
projectWhereClause,
pendingFeedbackStatus.Id
))
.SetResultTransformer(Transformers.AliasToEntityMap);
var results = query.List<IDictionary>();
return results.Select(r =>
new FeedbackTypeSummary
{
Type = Get(Convert.ToInt32(r["FEEDBACK_TYPE_ID"])),
AllFeedbackCount = Convert.ToInt32(r["ALL_FEEDBACK_COUNT"]),
PendingFeedbackCount = Convert.ToInt32(r["PENDING_FEEDBACK_COUNT"])
}).ToList();
and here is what I have so far (which is mostly everything minus the correlated subqueries and some additional filtering added to the subqueries):
var pendingFeedbackStatus = Session.QueryOver<FeedbackStatus>().Where(fs => fs.Name == "pending");
Feedback feedbackAlias = null;
FeedbackType feedbackTypeAlias = null;
var allFeedback = QueryOver.Of<Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived);
var pendingFeedback = QueryOver.Of<Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived)
.Where(f => f.Status.Id == pendingFeedbackStatus.Id);
var foo = Session.QueryOver<Feedback>(() => feedbackAlias)
.Right.JoinAlias(f => f.Type, () => feedbackTypeAlias, ft => !ft.IsRestricted)
.SelectList(list => list
// TODO: Add correlated subqueries here?
.SelectGroup(() => feedbackTypeAlias.Id)
.SelectGroup(() => feedbackTypeAlias.SortOrder)
)
.OrderBy(() => feedbackTypeAlias.SortOrder).Asc;
var test = foo.List<object[]>();
I'd also like to find a way to return a full FeedbackType entity of from the statement, instead of returning feedbackTypeAlias.Id and then having to perform Type = Get(Convert.ToInt32(r["FEEDBACK_TYPE_ID"])) in a loop as I do in the original.
I felt like I looked for this 10 times, but I overlooked the .SelectSubQuery() method which provided the desired correlated subqueries. This answer tipped me off - https://stackoverflow.com/a/8143684/191902.
Here is the full QueryOvery version:
var pendingFeedbackStatus = Session.QueryOver<FeedbackStatus>().Where(fs => fs.Name == "pending").SingleOrDefault();
Domain.Feedback.Feedback feedbackAlias = null;
FeedbackType feedbackTypeAlias = null;
var allFeedback = QueryOver.Of<Domain.Feedback.Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived);
var pendingFeedback = QueryOver.Of<Domain.Feedback.Feedback>()
.Where(f => f.Type.Id == feedbackTypeAlias.Id)
.Where(f => !f.IsArchived)
.Where(f => f.Status.Id == pendingFeedbackStatus.Id);
if (project != null)
{
allFeedback.Where(f => f.Project.Id == project.Id);
pendingFeedback.Where(f => f.Project.Id == project.Id);
}
FeedbackTypeSummary result = null;
var query = Session.QueryOver<Domain.Feedback.Feedback>(() => feedbackAlias)
.Right.JoinAlias(f => f.Type, () => feedbackTypeAlias, ft => !ft.IsRestricted)
.SelectList(list => list
.SelectSubQuery(allFeedback.ToRowCountQuery()).WithAlias(() => result.AllFeedbackCount)
.SelectSubQuery(pendingFeedback.ToRowCountQuery()).WithAlias(() => result.PendingFeedbackCount)
.SelectGroup(() => feedbackTypeAlias.Id).WithAlias(() => result.TypeId)
.SelectGroup(() => feedbackTypeAlias.Name).WithAlias(() => result.TypeName)
.SelectGroup(() => feedbackTypeAlias.NamePlural).WithAlias(() => result.TypeNamePlural)
.SelectGroup(() => feedbackTypeAlias.SortOrder)
)
.OrderBy(() => feedbackTypeAlias.SortOrder).Asc
.TransformUsing(Transformers.AliasToBean<FeedbackTypeSummary>());
var results = query.List<FeedbackTypeSummary>();
return results;
I also was able to populate my FeedbackTypeSummary DTO from a single query, although I couldn't find a way to alias an entity and ended up extracting a few of the needed properties from FeedbackType into FeedackTypeSummary (which is probably a better thing to do anyways).

Convert string to guid in linq join query : conditional statement

I have linq query as below
using (RMPortalEntities _RMPortalEntities = new RMPortalEntities()) {
var _RSVP_ButtonLocations = _RMPortalEntities
.tbl_RSVP_ButtonLocation
.Join(_RMPortalEntities.tbl_RSVP_Setting,
_RSVP_ButtonLocation => Guid.Parse(_RSVP_ButtonLocation.ID),
_RSVP_Setting => _RSVP_Setting.RSVP_Button_Location_ID,
(_RSVP_ButtonLocation, _RSVP_Setting) => new { _RSVP_ButtonLocation, _RSVP_Setting })
.Join(_RMPortalEntities.tbl_Event,
_RSVP_ButtonLocation_RSVP_Setting => _RSVP_ButtonLocation_RSVP_Setting._RSVP_Setting.EventID,
_Event => _Event.ID,
(_RSVP_ButtonLocation_RSVP_Setting, _Event) => new { _RSVP_ButtonLocation_RSVP_Setting, _Event })
.Where(x => x._Event.Active == true
&& x._Event.ID == _EventID)
.Select(x => new
{
RSVP_ButtonLocations = x._RSVP_ButtonLocation_RSVP_Setting._RSVP_ButtonLocation.RSVP_ButtonLocation
});
return _RSVP_ButtonLocations.FirstOrDefault().RSVP_ButtonLocations;
}
But problem is linq query does not allow me to convert string to Guid value.
Could anyone give me suggestion please?
Building on CjCoax comment you can store an instance of GUID and then use it later in the query:
using (RMPortalEntities _RMPortalEntities = new RMPortalEntities()) {
var GUID = new Guid(_RMPortalEntities.tbl_RSVP_ButtonLocation.ID);
var _RSVP_ButtonLocations = _RMPortalEntities
.tbl_RSVP_ButtonLocation
.Join(_RMPortalEntities.tbl_RSVP_Setting,
_RSVP_ButtonLocation => GUID,
_RSVP_Setting => _RSVP_Setting.RSVP_Button_Location_ID,
(_RSVP_ButtonLocation, _RSVP_Setting) => new { _RSVP_ButtonLocation, _RSVP_Setting })
.Join(_RMPortalEntities.tbl_Event,
_RSVP_ButtonLocation_RSVP_Setting => _RSVP_ButtonLocation_RSVP_Setting._RSVP_Setting.EventID,
_Event => _Event.ID,
(_RSVP_ButtonLocation_RSVP_Setting, _Event) => new { _RSVP_ButtonLocation_RSVP_Setting, _Event })
.Where(x => x._Event.Active == true
&& x._Event.ID == _EventID)
.Select(x => new
{
RSVP_ButtonLocations = x._RSVP_ButtonLocation_RSVP_Setting._RSVP_ButtonLocation.RSVP_ButtonLocation
});
return _RSVP_ButtonLocations.FirstOrDefault().RSVP_ButtonLocations;
}

Categories