MVC5 combine db .Include with OrderBy - asp.net

In my controller I'm including Balances and RZiS like this
Analysis1Full analysis1Full = db.Analysis1Full
.Include(u => u.Balance)
.Include(r => r.RZiS)
.SingleOrDefault(u => u.Analysis1FullId == id);
//enter code here
it gives me right object. The point is that I want to sort Balance by string filed (Year). But it gives me an error:
Analysis1Full analysis1Full = db.Analysis1Full
.Include(u => u.Balance.OrderBy(y => y.Year))
.Include(r => r.RZiS)
.SingleOrDefault(i => i.Analysis1FullId == id);
Error:
An exception of type 'System.ArgumentException' occurred in EntityFramework.dll but was not handled in user code
Additional information: The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.

The reason why the exception is thrown is simply because it is designed this way. According to MSDN, the Include() only Specifies the related objects to include in the query results.
To have the children in an order, you can add an OrderBy() when accessing them or you'd need to load them in a different query.

I solved it like this ... it is working
Analysis1Full analysis1Full = db.Analysis1Full.Find(id);
analysis1Full.Balance = db.Balances.Where(t=>t.Analysis1FullId == analysis1Full.Analysis1FullId).OrderBy(y=>y.Year).ToList();
analysis1Full.RZiS = db.RZiS.Where(t => t.Analysis1FullId == analysis1Full.Analysis1FullId).OrderBy(y => y.Year).ToList();
do you think it's good approach ?

Related

Entity Framework Core - This may indicate either a bug or a limitation in EF Core

I want to load from a user the newest private chat messages.
My code to load the newest messages
public async Task<List<UserChatMessage>> GetUserPrivateChatMessagesAsync(string userId, string userChatPartnerId, int limit, int skip, CancellationToken cancellationToken) {
cancellationToken.ThrowIfCancellationRequested();
if (userId == null) throw new ArgumentNullException(nameof(userId));
if (userChatPartnerId == null) throw new ArgumentNullException(nameof(userChatPartnerId));
return await this.Context.Messages
.OrderBy(d => d.CreatedDate)
.AsNoTracking()
.Include(p => p.UserChatPartner)
.Where(u => u.UserId == userId && u.UserChatPartnerId == userChatPartnerId || u.UserChatPartnerId == userId && u.UserId == userChatPartnerId)
.TakeLast(limit)
.Skip(skip)
.ToListAsync(cancellationToken);
}
The following code throw this error:
System.InvalidOperationException: Processing of the LINQ expression 'DbSet<UserChatMessage>
.OrderBy(d => d.CreatedDate)
.Include(p => p.UserChatPartner)
.Where(u => u.UserId == __userId_0 && u.UserChatPartnerId == __userChatPartnerId_1 || u.UserChatPartnerId == __userId_0 && u.UserId == __userChatPartnerId_1)
.TakeLast(__p_2)' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
I changed .Take to .TakeLast and now I get the described error.
Database structure of UserChatMessage
I also tried to change ToListAsync to AsEnumerable without success.
I hope somebody understand the error and can help me.
Thanks in advance.
Regard Timo
The error means you are hitting current EF Core bug or limitation.
I changed .Take to .TakeLast and now I get the described error.
So you know what caused the issue. In general avoid LINQ methods having Last in name (like Last, LastOrDefault, TakeLast) - these have no direct equivalent in SQL world, hence have bigger chance to hit bugs/limitations (or just not supported) by query translators.
Instead, invert the ordering and use the corresponding First method.
Applying it to your case means replacing
.OrderBy(d => d.CreatedDate)
with
.OrderByDescending(d => d.CreatedDate)
and
.TakeLast(limit)
with
.Take(limit)

SelectMany doesn't work on cosmosDb for child properties?

When I try to use selectMany on queryable that I build against cosmosdb I always get exception:
The LINQ expression 'DbSet
.Where(t => t.Id == __timelineId_0)
.SelectMany(
source: t => EF.Property>(t, "GraduationEvents")
.AsQueryable(),
collectionSelector: (t, c) => new TransparentIdentifier(
Outer = t,
Inner = c
))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
The query doesn't matter, always when I use selectMany I get this error.
Example query:
await _dbContext.Timelines.Where(x => x.Id == timelineId).Select(x => x.GraduationEvents).SelectMany(x => x).ToListAsync();
My entity configuration:
public void Configure(EntityTypeBuilder<Timeline> builder)
{
builder.HasKey(x => x.Id);
builder.HasAlternateKey(x => x.Id);
builder.OwnsMany(x => x.GraduationEvents, x => x.OwnsMany(graduationEvent => graduationEvent.Subjects));
}
I also tried to use native cosmosClient but when I query the base with plain sql I get empty objects (all nulls). Any thoughts what am I doing wrong?
Sajid - I tried your soulution but the exception remains the same
Try calling directly .SelectMany() over the List property (GraduationEvents).
I usually then call AsDocumentQuery() to generate the query to CosmosDB and then execute that query to retrieve the results.
Some pseudo c# to clarify this a bit:
var query = this.documentClient.CreateDocumentQuery(uri, options)
.SelectMany(x => x.GraduationEvents).AsDocumentQuery();
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync());
}
Edit: This approach uses the native Azure DocumentClient library.

LINQ to Entities does not recognize the method despite the fact that there are no null values for the parameters being queried

I get the following exception:
System.NotSupportedException: 'LINQ to Entities does not recognize the method 'OARRS_Staff.Dtos.SearchRequestDto get_Item(Int32)' method, and this method cannot be translated into a store expression.'
strangely if i drop FirstOrDefault I don't have this issue but I really only need the single record or null
var statuschange = _context.StateChanges
.Include(m => m.Staff)
.Where(m => m.statusID == searchRequestDto[c].statusID
&& m.requestDetailID == searchRequestDto[c].requestDetailID)
.OrderByDescending(m => m.statusChangeID)
.FirstOrDefault();

EF Core: how to load a single item from collection-nav property?

I have one-to-many relationship between two entities: User (one) has Messages (many) collection.
There needs to display some information about User and at the same time needs to load single Message.
I try to do something like:
mycontext.Users.Where(..).Include(user => user.Messages.Take(1).First());
However this code throws ecxeption
InvalidOperationException: The property expression 'user=> {from
Message m in [chat].Messages select
[m] => Take(1) => First()}' is not valid. The expression should
represent a property access: 't => t.MyProperty'. For more information
on including related data, see
http://go.microsoft.com/fwlink/?LinkID=746393.
How can I solve it?
Pretty easy. Instead of trying to load a message from a user, load the user from the message:
mycontext.Messages.Where(..).Include(msg => msg.User);
In fact, you can do it easier for you:
mycontext.Messages
.Include(msg => msg.User)
.Where(msg => msg.User...);
So you don't have to filter on Message rather than on User
You cannot do that the way you have tried.You have to retrieve all the related messages from the db and after that filter it on the memory (IEnumerable) as shown below.
var useList= mycontext.Users.Where(..).Include(user => user.Messages);
foreach (var u in useList)
{
var message= u.Messages.Take(1).First();
}

.net mvc3 entity deep compare on Where

My Code for a controller:
public ViewResult Index(int? ProjectID)
{
var user = HttpContext.User;
User profile = db.Users.Where(d => d.Email == user.Identity.Name).Single();
var contracts = db.Contracts.Include(c => c.Project);
if (!user.IsInRole("Admin"))
{
contracts = contracts.Where(p => p.Project.Client == profile.Client );
}
if (ProjectID != null)
{
contracts = contracts.Where(u => u.ID == ProjectID);
}
return View(contracts.ToList());
}
This is suppose to pull up all of the contracts whose parent project has the same client fk as the user currently signed in unless they are an admin. This isn't working.
I am getting the following error when the non-admin's look at the page:
Unable to create a constant value of type
'MembershipExt.Models.Client'. Only primitive types ('such as Int32,
String, and Guid') are supported in this context.
Do I need to use a second include or something?
What is the data type for p.Project.Client? I'm guessing that it is a complex type (it has properties off of it). Perhaps what you want is something like this...
contracts = contracts.Where(p => p.Project.Client.ClientID == profile.Client.ClientID );
Obviously I don't know what the object looks like, but perhaps this helps.
contracts = contracts.Where(p => p.Project.Client == profile.Client );
i am guessing the problem is in the above line the right hand side of lambda needs to be of simple type that is int32, string etc but you are having a complex type i.e. p.Project.Client
This looks wrong
db.Users.Where(d => d.Email == user.Identity.Name)
looks like you are comparing email with name

Resources