Nested LINQ Method throwing a `Not Supported...` Exception - c#

This is a follow up from here -->multiple-sorting-on-linq-nested-method .
Basically, on let memberName = ... it is throwing this exception Method 'System.String MemberName(Int32)' has no supported translation to SQL. and I am not figuring out the solution.
Also, BLLCmo and BLLConnect actually use TWO different DataBases. The original app(not mine) uses 4 Seperate DB's so I am trying to make due.
BLLCmo.cs
public static DataTable GetAllMembers(Guid workerID)
{
var AllEnrollees = from enrollment in context.tblCMOEnrollments
where enrollment.CMOSocialWorkerID == workerID || enrollment.CMONurseID == workerID
join supportWorker in context.tblSupportWorkers on enrollment.EconomicSupportWorkerID equals supportWorker.SupportWorkerID into workerGroup
from worker in workerGroup.DefaultIfEmpty()
let memberName = BLLConnect.MemberName(enrollment.ClientID)
orderby enrollment.DisenrollmentDate ascending, memberName ascending
select new
{
enrollment.ClientID,
MemberName = memberName,
NurseName = BLLAspnetdb.NurseName(enrollment.CMONurseID),
SocialWorkerName =BLLAspnetdb.SocialWorkerName(enrollment.CMOSocialWorkerID),
enrollment.DisenrollmentDate,
enrollment.EnrollmentDate,
ESFirstName = worker.FirstName,
ESLastName = worker.LastName,
ESPhone = worker.Phone
};
var dataTable = AllEnrollees.CopyLinqToDataTable();
return dataTable;
}
BLLConnect.cs
public static String MemberName(Int32 personID)
{
var memberName = from person in context.tblPersons
where person.PersonID == personID
select person.FirstName + " " + person.LastName;
return memberName.SingleOrDefault();
}

The problem is that LINQ to SQL is trying to translate your method into SQL. Since MemberName isn't valid SQL, it gives up. Instead, you'll need to pull down the data you need from SQL and then call your methods (and sort) in a separate LINQ to Objects query:
public static DataTable GetAllMembers(Guid workerID)
{
var AllEnrollees =
from enrollment in context.tblCMOEnrollments
where enrollment.CMOSocialWorkerID == workerID || enrollment.CMONurseID == workerID
join supportWorker in context.tblSupportWorkers on enrollment.EconomicSupportWorkerID equals supportWorker.SupportWorkerID into workerGroup
from worker in workerGroup.DefaultIfEmpty()
select new
{
enrollment.ClientID,
enrollment.CMONurseID,
enrollment.CMOSocialWorkerID,
enrollment.DisenrollmentDate,
enrollment.EnrollmentDate,
ESFirstName = worker.FirstName,
ESLastName = worker.LastName,
ESPhone = worker.Phone
};
var result =
from enrollee in AllEnrollees.AsEnumerable()
let memberName = BLLConnect.MemberName(enrollee.ClientID)
orderby enrollee.DisenrollmentDate ascending, memberName ascending
select new
{
enrollee.ClientID,
MemberName = memberName,
NurseName = BLLAspnetdb.NurseName(enrollee.CMONurseID),
SocialWorkerName = BLLAspnetdb.SocialWorkerName(enrollee.CMOSocialWorkerID),
enrollee.DisenrollmentDate,
enrollee.EnrollmentDate,
enrollee.ESFirstName,
enrollee.ESLastName,
enrollee.ESPhone
};
return result.CopyLinqToDataTable();
}

Related

MongoDB Linq query in C# with filters

I am trying to do a LINQ query on several Mongo collections. All the collections have to be joined based on ApplicationId and an outer Join has to be done - so that persons that have no statuses are returned as well.
The JOIN part and everything around it works as expected. The problem is that when I add a filter to one of the collections, the whole thing breaks
An exception of type 'System.ArgumentException' occurred in System.Linq.Expressions.dll but was not handled in user code: 'Expression of type 'System.Collections.Generic.IEnumerable`1[CDM.Person]' cannot be used for parameter of type 'System.Linq.IQueryable`1[CDM.Person]' of method 'System.Linq.IQueryable`1[CDM.Person] Where[Person](System.Linq.IQueryable`1[CDM.Person], System.Linq.Expressions.Expression`1[System.Func`2[CDM.Person,System.Boolean]])''
Here is my query
var applications = _dbContext.GetCollection<Application>(typeof(Application).Name).AsQueryable().Where(
x => x.OrganizationID == TokenContext.OrganizationID);
var persons = _dbContext.GetCollection<Person>(typeof(Person).Name).AsQueryable().Where(p =>p.FirstName == "j");
var statuses = _dbContext.GetCollection<ApplicationStatus>(typeof(ApplicationStatus).Name).AsQueryable();
var mortgages = _dbContext.GetCollection<Mortgage>(typeof(Mortgage).Name).AsQueryable();
var statusQuery = from a in applications
join p in persons on a.ApplicationID equals p.ApplicationID
join s in statuses on a.ApplicationID equals s.ApplicationID into pas
join m in mortgages on a.ApplicationID equals m.ApplicationID into morgs
from subWHatever in pas.DefaultIfEmpty()
select new ApplicationStatusProjection
{
ApplicationId = a.ApplicationID,
FirstName = p.FirstName,
LastName = p.Surname,
Prefix = p.Prefix,
DateOfBirth = p.DateOfBirth,
Initials = p.Initials,
PostalCode = p.Addresses.First().PostalCode,
MortgageAmount = morgs.Sum(i => i.MortgageTotal) ?? 0,
StatusExpireAt = subWHatever.ExpireAt ?? DateTime.MinValue,
StatusMessageText = subWHatever.MessageText ?? "",
StatusMessage = subWHatever.MessageStatus ?? ""
};
if (!String.IsNullOrEmpty(orderBy))
{
statusQuery = statusQuery?.OrderBy(orderBy);
}
if (nrOfRecords != null)
{
statusQuery = statusQuery?.Take(nrOfRecords.Value);
}
// Execute the query
var result = statusQuery?.ToList();
return result;
I followed the guidelines here https://mongodb.github.io/mongo-csharp-driver/2.6/reference/driver/crud/linq/ and I also tried this
var statusQuery =
from a in applications
join p in persons on a.ApplicationID equals p.ApplicationID into pa
from paObject in pa.DefaultIfEmpty()
join s in statuses on paObject.ApplicationID equals s.ApplicationID into pas
But I got the same error as before.
Thank you in advance.
So after may tryouts I have discovered that you cannot filter before the join because of the way the LINQ query is translated to Mongo query.
The fix for this is to have the filtering afterwards, on the statusQuery object. In that case, the filtering has to happen on the projected object (so a new filter is needed).
See below how I solved it:
//get collections
var applications = _dbContext.GetCollection<Application>(typeof(Application).Name).AsQueryable().Where(
x => x.OrganizationID == TokenContext.OrganizationID);
var persons = _dbContext.GetCollection<Person>(typeof(Person).Name).AsQueryable();
var statuses = _dbContext.GetCollection<ApplicationStatus>(typeof(ApplicationStatus).Name).AsQueryable();
var mortgages = _dbContext.GetCollection<Mortgage>(typeof(Mortgage).Name).AsQueryable();
//query
var query = from a in applications
join p in persons on a.ApplicationID equals p.ApplicationID
join s in statuses on a.ApplicationID equals s.ApplicationID into applicationStatusView
join m in mortgages on a.ApplicationID equals m.ApplicationID into morgs
from subStatus in applicationStatusView.DefaultIfEmpty()
select new ApplicationStatusProjection
{
ApplicationId = a.ApplicationID,
FirstName = p.FirstName,
LastName = p.Surname,
Prefix = p.Prefix,
DateOfBirth = p.DateOfBirth,
Initials = p.Initials,
Addresses = p.Addresses ?? new List<Address>(),
PostalCode = p.Addresses.First().PostalCode,
MortgageAmount = morgs.Sum(i => i.MortgageTotal) ?? 0,
StatusExpireAt = subStatus.ExpireAt ?? DateTime.MinValue,
StatusMessageText = subStatus.MessageText ?? "",
StatusMessage = subStatus.MessageStatus ?? "",
StatusDate = subStatus.StatusDate
};
//filter & order
var filteredResult = ApplyFilters(query, searchCriteria);
if (!String.IsNullOrEmpty(orderBy))
{
filteredResult = filteredResult?.OrderBy(orderBy);
}
if (nrOfRecords != null)
{
filteredResult = filteredResult?.Take(nrOfRecords.Value);
}
// Execute the query
var result = filteredResult?.ToList();
return result;
And applying the filters (there is probably a smarter way to do this):
private IQueryable<ApplicationStatusProjection> ApplyFilters(IQueryable<ApplicationStatusProjection> query, ApplicationStatusProjectionSearch searchCriteria)
{
if (!string.IsNullOrEmpty(searchCriteria.FirstName))
{
query = query.Where(x => x.FirstName.ToLower().StartsWith(searchCriteria.FirstName));
}
if (!string.IsNullOrEmpty(searchCriteria.LastName))
{
query = query.Where(x => x.LastName.ToLower().StartsWith(searchCriteria.LastName));
}
if (!string.IsNullOrEmpty(searchCriteria.PostalCode))
{
query = query.Where(x => x.Addresses.Any(a => a.PostalCode.ToLower().StartsWith(searchCriteria.PostalCode)));
}
//other irrelevant filters
return query;
}

linq query for sql xml column

I would need to write a linq query in c# for the following sql query.
I have no issues in implementing where, not in, orderby and descending but the problem is to query a sql xml column
SELECT [ID]
,[QueuedTime]
,Parameters.query('data(Root/Root/#type)').value('.', 'varchar(500)') as CommandName //how to implement this line in linq
,[Status]
,[CurrentRetryCount]
,[MaxRetryCount]
,[RetryDelaySeconds]
,[CompletedTime]
,[LastTriedTime]
,[LastError]
,Parameters
,[PrincipalString]
FROM [AppServer].[dbo].[RequestQueue]
where interfacename = 'ICommunicationsService'
and MethodName = 'ProcessCommand'
and status not in (1,2)
order by id desc
The following query will meet where, not in and order by descending conditions. I am concerned about how do I implement
'Parameters.query('data(Root/Root/#type)').value('.', 'varchar(500)') as CommandName' in linq
var unwantedStatus = new[] { 1, 2 };
var operationTimedOutTasks = context.TblRequestQueues
.Where(t => t.MethodName == "ProcessCommand" && !unwantedStatus.Contains(t.Status))
.OrderByDescending(t => t.ID)
.ToList();
The following has resolved my issue.
var query = from queue in context.TblRequestQueues
where queue.MethodName == methodName
&& queue.InterfaceName == interfaceName
&& !unwantedStatus.Contains(queue.Status)
orderby queue.ID descending
select new
{
queue.QueuedTime,
queue.Parameters,
queue.Status,
queue.CurrentRetryCount,
queue.MaxRetryCount,
queue.RetryDelaySeconds,
queue.CompletedTime,
queue.LastTriedTime,
queue.LastError,
queue.PrincipalString
};
var operationTimedOutTasks = query.AsEnumerable()
.Select(t => new TblRequestQueueDto
{
QueuedTime = t.QueuedTime,
Parameters = t.Parameters,
CommandName = XDocument.Parse(t.Parameters).Element("Root").Descendants("Root").FirstOrDefault().Attribute("type").Value,
Status = t.Status,
CurrentRetryCount = t.CurrentRetryCount,
MaxRetryCount = t.MaxRetryCount,
RetryDelaySeconds = t.RetryDelaySeconds,
CompletedTime = t.CompletedTime,
LastTriedTime = t.LastTriedTime,
LastError = t.LastError,
PrincipalString = t.PrincipalString
}).ToList();
Try with XDocument. (using System.Xml.Linq;)
Example:
var operationTimedOutTasks = (from queue in context.TblRequestQueues
where queue.MethodName == "ProcessCommand"
&& !unwantedStatus.Contains(t.Status)
let xml = XDocument.Parse(queue.Parameters)
orderby queue.ID
select new
{
//Other columns
Parameters = xml.Descendants("Root").FirstOrdDefault().Attribute("type").Value
}).ToList();

Linq To SQL toList<class> - Invalid Cast

I am not sure what I am doing wrong. But the linq to sql is choking when I do a toList.
it is running this area of the select.
case RightSearchType.Text:
If put the results in a var variable and not use the ToList it runs fine gets the results no problem.
I have tried
ToList()
ToList<URRightsView>()
Both of them yield the same issue.
I wish to pass back a strongly type List when developers call this method.
Please keep in mind this is not finished code. This is the first time I am using LINQ to SQL and my very first test to see if I am doing it right.
Thus failing badly.
Any help in resolving the casting problem is truly appreciated :)
public static List<URRightsView> Search(string SearchText, long Id, RightSearchType SearchType)
{
List<URRightsView> dRights = null;
try
{
using (DataContext db = new DataContext(AppSettings.Settings.ConnectionString))
{
Table<URRights> tRights = db.GetTable<URRights>();
Table<URRoles> tRoles = db.GetTable<URRoles>();
Table<URApps> tApps = db.GetTable<URApps>();
Table<URRightRoleMapping> tMapRoles = db.GetTable<URRightRoleMapping>();
Table<URApplicationRight> tMapApps = db.GetTable<URApplicationRight>();
string results = string.Empty;
switch (SearchType) {
case RightSearchType.Application:
dRights = (from ma in tMapApps
join apps in tApps on ma.AppFK equals apps.AppId
join r in tRights on ma.RightFK equals r.RightId
where (r.Title.Contains(SearchText) || r.Description.Contains(SearchText)) && ma.AppFK == Id
orderby r.Title, apps.Name ascending
select new URRightsView
{
Title = r.Title,
Classification = r.Classification,
Description = r.Description,
RightId = URUtil.GetLong(r.RightId),
RightType = r.RightType,
AppName = apps.Name
}).ToList<URRightsView>();
break;
case RightSearchType.Role:
dRights = (from ma in tMapApps
join apps in tApps on ma.AppFK equals apps.AppId
join r in tRights on ma.RightFK equals r.RightId
join mr in tMapRoles on r.RightId equals mr.RightFK
where (r.Title.Contains(SearchText) || r.Description.Contains(SearchText)) && ma.AppFK == Id
orderby r.Title, apps.Name ascending
select new URRightsView
{
Title = r.Title,
Classification = r.Classification,
Description = r.Description,
RightId = URUtil.GetLong(r.RightId),
RightType = r.RightType,
AppName = apps.Name
}).ToList<URRightsView>();
break;
case RightSearchType.Text:
dRights = (from ma in tMapApps
join apps in tApps on ma.AppFK equals apps.AppId
join r in tRights on ma.RightFK equals r.RightId
where r.Title.Contains(SearchText) || r.Description.Contains(SearchText)
orderby r.Title, apps.Name ascending
select new URRightsView
{
Title = URUtil.GetString(r.Title),
Classification = URUtil.GetString(r.Classification),
Description = URUtil.GetString(r.Description),
RightId = URUtil.GetLong(r.RightId),
RightType = URUtil.GetLong(r.RightType),
AppName = URUtil.GetString(apps.Name)
}).ToList<URRightsView>();
break;
}
}
}
catch (Exception ex)
{
URErrors.HandleError(ex, UserName);
JavaScriptSerializer serial = new JavaScriptSerializer();
string error = "URRights.Search Method: Could not Search Text - " + SearchText + ", SearchType = " + SearchType.ToString() + ",Id = " + Id.ToString() + Environment.NewLine;
URErrors.HandleError(ex, UserName);
throw new Exception(error);
}
return dRights;
}
UPDATE WITH EXCEPTION
Message
Specified cast is not valid.
at System.Data.SqlClient.SqlBuffer.get_Int64()
at System.Data.SqlClient.SqlDataReader.GetInt64(Int32 i)
at Read_URRightsView(ObjectMaterializer`1 )
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at URCore.URSecurity.URRights.Search(String SearchText, Int64 Id, RightSearchType SearchType) in D:\Development\Websites\unravelingspirit\URCore\URSecuirty\URRights.cs:line 244

Performing GroupBy and Union using LINQ to fetch records

Here's the situation.
I am trying to perform a Union between two queries using LINQ. I have applied GroupBy in both queries, using anonymous types. I dont know exactly, but probably the usage of anonymous type is leading me to this issue where I am unable to perform that Union operation. It shows me exception like this :
'System.Linq.IQueryable' does not contain a
definition for 'Union' and the best extension method overload
'System.Linq.ParallelEnumerable.Union(System.Linq.ParallelQuery,
System.Collections.Generic.IEnumerable)' has some invalid
arguments
Here is the query :
var records = (from o in _context.Table1
join q in _context.Table2 on o.UserId equals q.UserId
group new { o, q }
by new { o.Name, o.Date, o.IsDone, o.IsDl, o.DateChanged, o.UserId, q.FirstName, q.LastName } into data
select new
{
NameP = data.Key.Name,
Date = data.Key.Date,
IsDone = data.Key.IsDone,
IsDl = data.Key.IsDl,
DateDone = data.Key.DateChanged,
Name = data.Key.FirstName +" "+ data.Key.LastName
}).Union(
from i in _context.Table1
where i.UserId == null
group i by new {o.Name, o.Date, o.IsDone, o.IsDl, o.DateChanged, o.UserId} into newData
select new
{
NameP = newData.Key.Name,
Date= newData.Key.Date,
IsDone = newData.Key.IsDone,
IsDl = newData.Key.IsDl,
DateDone = ' ',
Name = ' '
}).ToList();
What I am trying to achieve here is to get records of both cases, when UserId is null as well as when its not null using group by since records are repeated.
Any suggestions or guidance here on what I am doing wrong are appreciated.
Make sure that the two anonymous types have the same data type for all proprties.
The only ones I can speculate on are the date ones. Maybe the first DateDone is actually a DateTime type and you are setting the second one to a string...
var records = (from o in _context.Table1
join q in _context.Table2 on o.UserId equals q.UserId
group new { o, q }
by new
{
o.Name,
o.Date,
o.IsDone,
o.IsDl,
o.DateChanged,
o.UserId,
q.FirstName,
q.LastName
} into data
select new
{
NameP = data.Key.Name,
Date = data.Key.Date,
IsDone = data.Key.IsDone,
IsDl = data.Key.IsDl,
DateDone = data.Key.DateChanged,
Name = data.Key.FirstName +" "+ data.Key.LastName
}).Union(from i in _context.Table1
where i.UserId == null
group i by new
{
o.Name,
o.Date,
o.IsDone,
o.IsDl,
o.DateChanged,
o.UserId
} into newData
select new
{
NameP = newData.Key.Name,
Date = newData.Key.Date,
IsDone = newData.Key.IsDone,
IsDl = newData.Key.IsDl,
DateDone = new DateTime(0),
Name = ' '
}).ToList();

LINQ query with List<> and asking if is null

I have some method with linq query. Logic is next, if I pass null for list of role ids, I want all roles to be included in process, but if it has value, I want only those with id in the list. I am receiving exeption.
public static List<NameEmail> GetNameEmailPairs(Guid guid, List<int> recipientRoles)
{
using (var tc = TransactionContext())
{
var dc = tc.DataContext;
var nameEmailPairs = (
from email in dc.Emails
join logon in dc.Logons on email.GUID equals logon.GUID
join eLogon in dc.ELogons on logon.UID equals eLogon.LogonGUID
join role in dc.Roles on entityLogon.PrimaryPermissionRoleID equals role.RoleID
where
(recipientRoles == null || recipientRoles.Contains(role.RoleID))
select new NameEmail
{
Email = email.EmailAddress,
FullName = GetName(logon.GUID)
}
)
.ToList();
return nameEmailPairs;
}
}
This part is breaking (recipientRoles == null || recipientRoles.Contains(role.RoleID)). Can you please help me with this, what should I do?
To make debugging easier, break your query up into pieces like this:
var nameEmailPairs = (
from email in dc.Emails
join logon in dc.Logons on email.GUID equals logon.GUID
join eLogon in dc.ELogons on logon.UID equals eLogon.LogonGUID
join role in dc.Roles on entityLogon.PrimaryPermissionRoleID equals role.RoleID
select new {email, role}
);
if(recipientRoles != null)
{
nameEmailPairs = nameEmailPairse.Where(
recipientRoles.Contains(p => p.role.RoleID)
);
}
var nameEmailPairs = (from p in nameEmailPairs
select new NameEmail
{
Email = email.EmailAddress,
FullName = GetName(logon.GUID)
}).ToList();

Categories