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();
Related
I need to build a search query with dynamic parameters in net core 3.0.
IQueryable<UserDto> query =
from user in dbContext.DB_USER
join items in dbContext.DB__ITEMS on user.IdItem equals items.IdItem
join cars in dbContext.DB_CARS on user.IdCars equals cars.IdItem
join statsCar in dbContext.DB_STATS_CARS on cars.IdCars equals statsCar.Id
select new UserDto
{
Id = user.Id,
Name = user.Name,
Data = user.Data.HasValue ? user.Data.Value.ToUnixTime() : default(long?),
Lvl = user.L,
Items = new ItemsUdo
{
Id = items.Id,
Type = items.Type,
Value = items.Value
},
Cars = new CarsDto
{
Id = cars.Id,
Model = cars.model,
Color = cars.Color
}
};
I would like to add search parameters like user name, items type, cars model and data from user. I tried to add "where" before 'select new UserDto' but not always user will provide all search parameters. If I give below:
if(fromSearch.UserName != null && fromSearch.UserName.Lenght > 0)
{
query = query.Where(u => u.Name == fromSearch.UserName);
}
it works(on user.data does not work) but is it correct? How to do this in linq query?
Do something like this:
IQueryable<UserDto> query =
from user in dbContext.DB_USER
join items in dbContext.DB__ITEMS on user.IdItem equals items.IdItem
join cars in dbContext.DB_CARS on user.IdCars equals cars.IdItem
join statsCar in dbContext.DB_STATS_CARS on cars.IdCars equals statsCar.Id;
select new UserDto
{
Id = user.Id,
Name = user.Name,
Data = user.Data.HasValue ? user.Data.Value.ToUnixTime() : default(long?),
Lvl = user.L,
Items = new ItemsUdo
{
Id = items.Id,
Type = items.Type,
Value = items.Value
},
Cars = new CarsDto
{
Id = cars.Id,
Model = cars.model,
Color = cars.Color
}
};
if(!string.IsNullOrWhitespace(username))
query = query.Where(ud => ud.Name == username);
if(!string.IsNullOrWhitespace(itemtype))
query = query.Where(ud => ud.Items.Any(i => i.Type == itemtype));
if(!string.IsNullOrWhitespace(carmodel))
query = query.Where(ud => ud.Cars.Any(c => c.Model == carmodel));
etc. These will work like AND; if you specify a username and an itemtype you get only those users named that, with that item type somewhere in the items list.. etc
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;
}
I am trying to fill select tag options from JQuery ajax call. I am using Asp.Net Core 2.1 Razor Pages, and PostgreSQL as DB.
Here is my Server side LINQ code
[HttpGet]
public ActionResult TypeofAccounts()
{
var result = (from N in _POSContext.TypeOfAccounts
select new { label = N.AccountType, id = N.AccountType });
return Json(result);
}
It works fine. Now, I want to sort those results from LINQ so I tried following ways but it always encounters Npgsql Exception "column \"label\" does not exist"
var result = (from N in _POSContext.TypeOfAccounts.OrderBy(x=>x.AccountType)
select new { label = N.AccountType, id = N.AccountType });
var result = (from N in _POSContext.TypeOfAccounts
select new { label = N.AccountType, id = N.AccountType }).OrderBy(x => x.label);
var result = (from N in _POSContext.TypeOfAccounts.OrderBy(x => x.AccountType)
where N.AccountType != null
select new { label = N.AccountType, id = N.AccountType });
I could see coloumn is missing in generated sql.
{SELECT x."AccountType" AS id
FROM "TypeOfAccounts" AS x
WHERE x."AccountType" IS NOT NULL
ORDER BY label}
You need to invoke the query from the database using ToList method, then selecting your object, like this:
var result = _POSContext.TypeOfAccounts
.Where(x => x.AccountType != null)
.OrderBy(x => x.AccountType)
.ToList()
.Select(x =>
new
{
label = x.AccountType,
id = x.AccountType
}
);
You can try this
var result = _POSContext.TypeOfAccounts
.Where(x => x.AccountType != null)
.OrderBy(x => x.AccountType)
.ToList()
.Select(x =>
new
{
label = x.AccountType,
id = x.AccountType
}
);
I have to download some complex datas from database which aggregate lots of usefull infos about post. I would like to do something like this:
var list = (from message in db.BLOGS_MESSAGES
where message.BLOG_ID == blogId
orderby message.CREATED_DATE descending
select new BlogMessage()
{
AUTHORS = **(from author in message.AUTHORS
select author.USERS).ToArray()**,
CREATED_BY = message.CREATED_BY,
CREATED_DATE = message.CREATED_DATE,
BLOG_MESSAGE_ID = message.POST_ID,
MESSAGE_TITLE = message.TITLES.TITLE,
TAGS = **(from tag in message.TAGGED_MESSAGES
select tag.TAGS).ToArray()**,
LOGIN = message.USERS.LOGIN,
MESSAGE = message.MESSAGES.MESSAGE,
MESSAGE_ID = message.MESSAGE_ID,
POST_NOTE = message.POST_NOTES.Sum(x => (long?)x.NOTE) ?? 0 / message.POST_NOTES.Count(),
}).ToList();
but it doesn't work. It throws an exception that can't translate expression in store expression.
so far i did it in this way:
var mlist = (from message in db.BLOGS_MESSAGES
where ....
orderby ....
select new {
AUTHORS = (from author in message.AUTHORS
select author.USERS),
....
}
List<BlogMessage> list = new List<BlogMessage>();
foreach(var item in mlist)
{
list.Add(new BlogMessage()
{
AUTHORS = item.AUTHORS.ToArray(),
...
});
}
is it possible to make it work 'in first way - style'?
You can either:
Change BlogMessage.AUTHORS to be an IEnumerable<USERS> and remove the .ToArray() calls in the query like Grundy suggested.
Bring the results into memory before creating BlogMessage's.
For example:
var step1 = db.BLOGS_MESSAGES
.Where(...)
.Select(message => new {
Authors = message.AUTHORS.Select(a => a.USERS), // No .ToArray()
...
}).ToList();
var step2 = step1.Select(message => New BlogMessage {
Authors = message.Authors.ToArray(),
...
}).ToList();
I have this piece of code
var tblGrouped = dtCSV.AsEnumerable()
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
});
But I want to add an additional column to filter by. Basically if course_type_id = 1 for example. dtCSV is the source where the course_type_id is populated. I tried the following but it didn't work:
var tblGrouped = dtCSV.AsEnumerable()
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
course_type_id = "1",
});
If I understand your requirement correctly, you want to group rows which have a course_type_id of 1?
var tblGrouped = dtCSV.AsEnumerable()
.Where(r => r.Field<String>("course_type_id") == "1")
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
});
To filter by use Where syntax
Ex. .Where(a=>a.Field<String>("course_type_id") == "1")
You'll want to add the condition first. You can do that using .Where:
var tblGrouped = dtCSV.AsEnumerable()
.Where(r => r.Field<String>("course_type_id") == "1")
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
course_type_id = "1"
});