Odata V4 group by with Top and skip not working - group-by

I am not able to get groupby to work with top and skip which should be most simplest thing.
I am fetching data using OData and able to get output using the query below
https://localhost:6523/api/OData/AssetUsage/?$apply=groupby((assetId,BIAsset/name),aggregate(interactions with sum as totalInteractions, uniqueInteractions with sum as totalUniqueInteractions))&$orderBy=totalInteractions asc
Output of the above query
However when I try to apply skip or top on the above generated output, I get an error mentioned below
https://localhost:6523/api/OData/AssetUsage/?$apply=groupby((assetId,BIAsset/name),aggregate(interactions with sum as totalInteractions, uniqueInteractions with sum as totalUniqueInteractions))&$orderBy=totalInteractions asc&$top=1
Error -
message": "The query specified in the URI is not valid. Could not find a property named 'BIAsset' on type 'Portal.Models.Entities.AssetUsage'.",
"innererror":
-"message": "Could not find a property named 'Asset' on type 'Portal.Models.Entities.AssetUsage'.",
-"type": "Microsoft.OData.ODataException",
Entity class structure
public class AssetUsage
{
public int Id { get; set; }
[ForeignKey("BIAsset")]
public int? AssetId { get; set; }
public int YearMonthId { get; set; }
public int Interactions { get; set; }
public int UniqueInteractions { get; set; }
public DateTimeOffset Recency { get; set; }
public virtual BIAsset BIAsset { get; set; }
}

I was using EnableLowerCamelCase() so I need to use exact casing while writing a query.
However in future update this issue will be resolved.
refer to below URL for further updates.
https://github.com/OData/WebApi/issues/1659

Related

REST API - appropriate method and route to have child change what its parent resource is

Let's say I have 2 models, Location and Item, that correspond to 2 tables in a database, represented in c# below. Is something like a PATCH request to /items/{itemId} appropriate to change the location id of an item to refer to a different location resource? This is the first time I've been in a situation where I want to change the parent of a resource so I am unsure of the appropriate method and route. I'm working with DTO (data transfer objects) so ideally what I want to do is acceptable so I can have just one DTO patch class for updates to the Item model.
public class Location {
public long Id { get; set; }
public ushort RoomNumber { get; set; }
public string Description { get; set; }
public List<Item> Items { get; set; }
}
public class Item {
public long Id { get; set; }
public string AssetNumber { get; set; }
public string SerialNumber { get; set; }
public long LocationId { get; set; }
public Location Location { get; set; }
}
Given that your url is /items/{itemId} and not something like /location/{locationId}/items/{itemId}, I don't think there's any thing special about changing the locationId versus any other property from a HTTP/Rest perspective.
And PATCH is a good way to make a partial change to a resource.

Entity-Framework-Core: Mapping 1 to 1 Relationships using Composite Keys

I'm having difficult configuring a 1:1 mapping in EntityFrameworkCore using FluentAPI. The navigational reference is always NULL. The only obvious difference between my code and countless others I have examined is I am trying to map via composite keys.
I've played around using annotations instead of Fluent API but encounter the same issue described in my summary.
Class Definitions
[Table("SomeTable")]
public class Defect
{
[Column("Record")]
public int DefectId { get; set; }
[Column("insp_id")]
public int InspId { get; set; }
[Column("defectnum")]
public int Number { get; set; }
public virtual Simulation Simulation { get; set; }
}
[Table("SomeSimulationTable")]
public class Simulation
{
[Column("Record"), Key]
public int SimTableId { get; set; }
[Column("insp_id")]
public int InspId { get; set; }
[Column("DefectNumber")]
public int Number { get; set; }
[Column("SimulationName")]
public string Name{ get; set; }
[Column("SimulationAlgorithm")]
public string Algorithm{ get; set; }
public virtual Defect Defect { get; set; }
}
Fluent API (in OnModelCreating)
modelBuilder.Entity<Defect>()
.HasKey(h => new { h.InspId , h.Number });
modelBuilder.Entity<Defect>()
.HasOne<Simulation>(p => p.Simulation)
.WithOne(i => i.Defect)
.HasForeignKey<Simulation>(b => new { b.InspId , b.Number });
When the "Defect" class is populated through the dbContext all data is available; however, when I attempt to access the "Simulation" property of the "Defect" class I encounter the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I have also verified there is valid data in our database where the "Defect" should have a "Simulation".
Any help? Throwing myself at the mercy of other coders....
Take a look at the Include method when loading from the database, it will be null unless you explicitly load:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entityframeworkqueryableextensions.include?view=efcore-2.1
https://entityframeworkcore.com/querying-data-include-theninclude

Why do I need to call LoadAsync before querying over the same?

NOTE: This is Entity Framework 7 / Entity Framework Core running on DNX.
I have the following two models:
public class ProductTag
{
[Key]
public Guid Id { get; set; }
[Required]
public Guid TagId { get; set; }
public Tag Tag { get; set; }
[Required]
public Guid ProductId { get; set; }
public Product Product { get; set; }
}
public class Product
{
[Key]
public Guid Id { get; set; }
[Required]
public String Name { get; set; }
[Required]
public UInt32 Price { get; set; }
public List<ProductTag> Tags { get; set; } = new List<ProductTag>();
}
When I try to execute the following query, it fails to find any matches:
await _bagsContext.Products
.Where(product => expectedTagIds
.All(expectedTagId => product.Tags
.Select(productTag => productTag.TagId)
.Contains(expectedTagId)))
.ToListAsync();
Note: When I run the following query I get the full results, including the Tags!
await _bagsContext.Products.ToListAsync()
This suggests that it is the Where clause specifically that doesn't have the necessary things populated. Perhaps this is an issue (as suggested in the comments) of the Where clause being executed client side before the DB is queried for the Products.
The goal of the query is to return a list of products that have every expectedTagId on them.
For a simple example take the two products
apple - tags: fruit, round
banana - tags: fruit, long
Given a call to the above code with expectedTagIds for the tags fruit and round would only return apple.
I managed to fix my issue and get the above query to work by adding the following line above the call.
Task.WaitAll(_bagsContext.ProductTags.LoadAsync(), _bagsContext.Products.LoadAsync());
I kind of understand why ProductTags needs to be pulled in, I assume that LINQ to Entities doesn't drill deep enough into the Where clause to realize that it needs the tags when it compiles the query.
However, I can't fathom why I need to call LoadAsync() on Products. Products is the table I am querying over.

How Do I Resolve "A specified Include path is not valid"?

I have a parent-child relationship setup that is fairly basic. The end result is that I want to be able to return the resulting tables as JSON through ASP.NET MVC WebAPI. I am using Entity Framework 5.0 beta 2.
I can demonstrate the error I'm running into with a simple example. Given the classes Category and Product with the corresponding data context:
public class Category
{
public int CategoryId { get; set; }
public string Title { get; set; }
public virtual IEnumerable<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Title { get; set; }
public virtual Category Category { get; set; }
public virtual int CategoryId { get; set; }
}
public class ProductDataContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
When I try to run a query that includes the products I get the following error:
A specified Include path is not valid. The EntityType 'FooAndBar.Category'
does not declare a navigation property with the name 'Products'.
The statement to fetch is pretty straightforward:
var everything = dc.Categories
.Include(c => c.Products);
What is the correct way to setup the columns and/or the query so that the Products are included with the Categories?
Child collection properties must be declared as anICollection<T>, not anIEnumerable<T>.
Also, you do not need to explicitly add a CategoryId field to the child class; EF will create that automatically in the database.

EF CTP4 Missing columns in generated table

I'm having an issue that i just can't seem to figure out. Lets say I have 2 Entities defined in my domain; Person and Document. Below is the definition for Document :
public class Document
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Title { get; set; }
public DateTime Date { get; set; }
public virtual Person Owner{ get; set; }
public virtual Person AssignedTo { get; set; }
}
Now, when EF CTP4 creates the SQL table on initialize, there is only one field mapping to a Person.Id being Owner_id. Whatever i try, the field for AssignedTo is never created.
Anything that could solve this?
Regards,
avsomeren
Your code perfectly created the desired schema in the database for me:
If you don't get this schema in you DB then my guess is that something is not right with the rest of your object model. Could you post your full object model please?
Another Solution:
While your current Document class will give you the desired results, but you can still take advantage of the Conventions for Code First and explicitly specify the FKs for your navigation properties:
public class Document
{
public int Id { get; set; }
[Required][StringLength(255)]
public string Title { get; set; }
public DateTime Date { get; set; }
public int OwnerID { get; set; }
public int AssignedToID { get; set; }
public virtual Person Owner { get; set; }
public virtual Person AssignedTo { get; set; }
}
Code First will now infer that any property named <navigation property name><primary key property name> (e.g. OwnerID), with the same data type as the primary key (int), represents a foreign key for the relationship.
This essentially results to the same DB schema plus you have the FKs on your Document object as well as navigation properties which gives you ultimate flexibility to work with your model.