How can I solve my error below with a query? - c#

When running this code:
public async Task<IActionResult> AddMessage()
{
int distid = ViewBag.DISTRIBUTORID;
ViewBag.PageName = "Send Message";
int id = Convert.ToByte(ViewBag.ID);
ViewBag.UserId = id;
var messages = await _companyContext.MESAJLAR.Where(p => p.SENDERID == id || p.SENTID == id).OrderBy(p => p.DATE).GroupBy(p => p.SPECIALID).Select(p => p.Last()).ToListAsync();
var ids1 = messages.Select(p => p.SENDERID).ToArray();
var ids2 = messages.Select(p => p.SENTID ).ToArray();
var users= await _userDatabaseContext.user.Where(p => p.DISTID == distid && p.ID != id && !ids1.Contains(p.ID) && !ids2.Contains(p.ID)).ToListAsync();
return View(new AddMessageViewModel
{
USERS= users
});
}
I get the following error:
Queries performing 'Last' operation must have a deterministic sort order.Rewrite the query to apply an 'OrderBy' operation on the sequence before calling 'Last'.
I'm getting it at the line that starts with var messages = ...

The Problem with your query is, that you are trying to select .Last() without ordering your data first.
Right now you are ordering your data, then group it and after that you try to select 'Last()'.
You have to order the grouped data to use '.Last()'.
var messages = await _companyContext.MESAJLAR.Where(p => p.SENDERID == id || p.SENTID == id).OrderBy(p => p.DATE).GroupBy(p => p.SPECIALID).OrderBy(p => p.XXXXX).Select(p => p.Last()).ToListAsync();
And your first order would probably be not needed anymore.

Related

Entity Framework Core - Get multiple rows from one table as one DTO with multiple properties

Is it possible to select two rows into one anonymous object DTO with two properties?
With a model like:
public class Document
{
public int Id { get; set; }
public string Text { get; set; }
// Other properties
}
I am writing a method that finds the difference between two versions of a document:
public Task<string> CompareVersions(int initialId, int finalId)
So I need to retrieve the text of exactly two Documents by Id, and I need know which was which.
Currently I am constructing a Dictionary<int, string> by doing:
var dto = await _context.Documents
.Where(doc => doc.Id == initialId
|| doc.Id == finalId)
.ToDictionaryAsync(x => x.Id, x => x.Text);
and then calling dto[initialId] to get the text. However, this feels very cumbersome. Is there any way to take the two Ids and select them into one DTO in the form
{
InitialText,
FinalText
}
You have to use SelectMany
var query =
from initial in _context.Documents
where initial.Id = initialId
from final in _context.Documents
where final.Id = finalId
select new
{
InitialText = initial.Text,
FinalText = final.Text
};
var result = await query.FirstOrDefaultAsync();
Aggregate can do it too
var dto = (await _context.Documents
.Where(doc => doc.Id == initialId || doc.Id == finalId).ToListAsync())
.Aggregate(
new { InitialText = "", FinalText = "" },
(seed, doc) => {
if(doc.Id == initialId)
seed.InitialText = doc.Text;
else
seed.FinalText = doc.Text;
}
);
I'm not sure I like it any more than I do your dictionary approach, but with an actual dto at the end rather than the dictionary:
var d = await _context.Documents
.Where(doc => doc.Id == initialId || doc.Id == finalId)
.ToDictionaryAsync(x => x.Id, x => x.Text);
var dto = new { InitialText = d[initialId], FinalText = d[finalId] };
You could also perhaps just:
var dto = new {
InitialText = await context.Documents
.FindAsync(initialId),
FinalText = await context.Documents
.FindAsync(finalId)
};

Problem returning entity grouped with LINQ in HTTP GET

What I'm doing wrong in this method below? I created a group with linq because I need to group the list by 2 columns and for this grouping I will have a list of files.
[HttpGet]
[Route("versions-by-period")]
public IActionResult GetVersionsByPeriodId(int entityId, int periodId)
{
var versionsInvoiceBillet = db.RemittanceInvoiceBilletVersionsCompacts
.Where(x => x.LegalEntityId == entityId && x.PeriodId == periodId && x.IsCurrent && x.DownloadHash != null)
.GroupBy(x => new { x.LifePolicyNumber, x.LegalEntityGroupNumber },
i => new { i.DownloadHash, i.FileTypeEnum, i.DueDate }, (key, group) => new
{
LifePolicyNumber = key.LifePolicyNumber,
LegalEntityGroupNumber = key.LegalEntityGroupNumber,
Files = group.ToList()
});
return Ok(versionsInvoiceBillet.Select(x => new {
lifePolicyNumber = x.LifePolicyNumber,
legalEntityGroupNumber = x.LegalEntityGroupNumber,
invoiceAndBillet = x.Files.Select(f => new {
downloadHash = f.DownloadHash,
fileTypeEnum = f.FileTypeEnum,
dueDatet = f.DueDate
})
}));
}
If I try to call this method with Postman, the body comes empty. The problem is in invoiceAndBillet information that is returned, if I change to below, the body comes filled.
return Ok(versionsInvoiceBillet.Select(x => new {
lifePolicyNumber = x.LifePolicyNumber,
legalEntityGroupNumber = x.LegalEntityGroupNumber,
invoiceAndBillet = x.Files.Select
}));
If I try to debug the selection that I'm trying to return, I get this message below:

c# winforms, using async and await in a Search function

I'am trying to search employees by using async and await with button function, but my code doesn't work as my expect and get error like "requires a receiver of type 'IQueryable'". How should I do if I want to use async await in windows form.
Here is my code: Thank you in advance!
private async void btnSearch_Click(object sender, EventArgs e)
{
using(db)
{
var employees = db.Analys
.Where(x => x.Status == true)
.Select(a => new { a.UserId, a.FirstName, a.LastName, a.DOB, a.Department, a.DepartmentId })
.AsEnumerable()
.Select(b => new {
UserId = b.UserId,
FirstName = b.FirstName,
LastName = b.LastName,
Age = CalculateAge(b.DOB.ToString()),
Department = b.Department.DepartmenName,
});
var data = await employees.ToListAsync();
if (data!= null)
{
dgvEmployees.DataSource = data;
}
}
}
Can you please add full error text? But from the code you've already provided I assume you are using Entity Framework to access your DB, so AsEnumerable() should already have materialized the data fetching it from db. I would say that you don't need it here, and first Select clause too. Try something like this:
var employees = await db.Analys
.Where(x => x.Status == true)
.Select(b => new {
UserId = b.UserId,
FirstName = b.FirstName,
LastName = b.LastName,
Age = CalculateAge(b.DOB.ToString()),
Department = b.Department.DepartmenName,
})
.ToListAsync();
Also the null check should not be needed here, cause EF should return empty collection.

How to sort data based on CreatedUtc Date using mongodb query in c#?

I want to sort the data based on CreatedUtc time. I have tried to use Reverse function, it seems to work out but still looking for some alternate option.
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).ToList().Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().ToList();
There are 2 things you need to concern:
You can sort the elements of a sequence by using OrderBy
You should not .ToList() when you have not done, So you might to read LINQ deferred (or immediate?) execution to have a better understanding.
As a result, your query should look like this
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().OrderBy(g => g.CreatedUtc).ToList();
How about .OrderBy(g => g.CreatedUtc) ?

LINQ's SelectMany Equivalent in OData

I have an entity called AccountAction that has property called TransactionTypes that is an ICollection of TransactionType entities.
I return a list of all the TransactionTypes that are related to all the AccountActions in a method called GetTransactionTypes. I would like to apply query options to the returned list of TransactionTypes. However, so far I have hit a wall because all of the query options are applied to AccountActions.
Is there any way I can apply query options in the URL to the returned lists of TransactionTypes? In other words, is there a way I can do a SelectMany from the URL to get the TransactionTypes related to the AccountActions to move on to apply the query options to the found TransactionTypes?
Below is an extract of the code that I am using.
[Route(FullControllerPath + "/TransactionTypes")]
public IHttpActionResult GetTransactionTypes(ODataQueryOptions<AccountAction> queryOptions, bool addCols, int? skip, int? take)
{
using (AccountActionManagement _accountActionManage = new AccountActionManagement(this.GenerateInformation()))
{
_accountActionManage.SetTraslationList("DATASTRUCT-CONFIG-ACCOUNTACTIONTRANSACTIONTYPE", language);
// Query composition
IQueryable<TransactionType> query = queryOptions.ApplyTo(_accountActionManage.GetTypeAsQueryable<AccountAction>())
.OfType<AccountAction>()
.SelectMany(aa => aa.TransactionTypes)
.Include(tt => tt.AccountActionForDefaultTransactionType.DefaultTransactionType);
var queryData = query.Select(tt => new
{
Id = tt.Id,
Name = tt.Name,
Operation = tt.Operation,
Type = tt.Type,
Default = tt.AccountActionForDefaultTransactionType != null &&
tt.AccountActionForDefaultTransactionType.DefaultTransactionType.Id == tt.Id,
Version = tt.AccountActionForDefaultTransactionType.Version
});
// Get count
int totalRows = queryData.Count();
// Get biggest version in query
var maxVersion = queryData.Max(i => i.Version);
// Get data from database
var queryResult = queryOptions.OrderBy == null
? queryData.OrderBy(i => i.Id)
.Skip(skip ?? 0)
.Take(take ?? totalRows)
.ToList()
: queryData.Skip(skip ?? 0)
.Take(take ?? totalRows)
.ToList();
...}}
As seen in the diagram below, AccountAction has a many-to-many relationship to TransactionType. AccountAction has the first role and TransactionType has the second role.
I found a workaround for this issue. I realized that I was not passing the right type to the ApplyTo method. Now, I apply the query options to an IQueryable of TransactionTypes instead of applying the query options to an IQueryable of AccountActions.
Below is the code with the described modification. Also, a diffchecker of the change I made is here.
[Route(FullControllerPath + "/TransactionTypes")]
public IHttpActionResult GetTransactionTypes(ODataQueryOptions<AccountAction> queryOptions, bool addCols, int? skip, int? take)
{
using (AccountActionManagement _accountActionManage = new AccountActionManagement(this.GenerateInformation()))
{
_accountActionManage.SetTraslationList("DATASTRUCT-CONFIG-ACCOUNTACTIONTRANSACTIONTYPE", language);
// Query composition
IQueryable<TransactionType> query = queryOptions.ApplyTo(_accountActionManage.GetTypeAsQueryable<AccountAction()
.SelectMany(aa => aa.TransactionTypes)
.Include(aa => aa.AccountActionForDefaultTransactionType.DefaultTransactionType))
.OfType<TransactionType>();
var queryData = query.Select(tt => new
{
Id = tt.Id,
Name = tt.Name,
Operation = tt.Operation,
Type = tt.Type,
Default = tt.AccountActionForDefaultTransactionType != null &&
tt.AccountActionForDefaultTransactionType.DefaultTransactionType.Id == tt.Id,
Version = tt.AccountActionForDefaultTransactionType.Version
});
// Get count
int totalRows = queryData.Count();
// Get biggest version in query
var maxVersion = queryData.Max(i => i.Version);
// Get data from database
var queryResult = queryOptions.OrderBy == null
? queryData.OrderBy(i => i.Id)
.Skip(skip ?? 0)
.Take(take ?? totalRows)
.ToList()
: queryData.Skip(skip ?? 0)
.Take(take ?? totalRows)
.ToList();
...}}

Categories

Resources