How to use Paging in breeze on expanded entities? - entity-framework

I'm writting a web application using EF on the server side and breeze on the client side.
I have the following classes defined in EF:
public class Product
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("Product")]
public virtual ICollection<Property> Properties { get; set; }
}
public class Property
{
[Key]
public int Id { get; set; }
public string Type { get; set; }
public string Name { get; set; }
public string DefaultValue { get; set; }
[ForeignKey("Product")]
public int ProductId { get; set; }
public Product Product { get; set; }
}
public class PropValue
{
[Key]
[Column(Order = 0)]
[InverseProperty("RecordId")]
public int RecordId { get; set; }
public Property Record { get; set; }
[Key]
[Column(Order = 1)]
public int PropertyId { get; set; }
public Property Property { get; set; }
public string Value { get; set; }
}
These classes allows me to create at runtime various 'Products' each having any number of 'Properties' (the name of the property is in 'Property', the value of the property is in 'PropValue').
On the client side, I need to retrieve the Products in
breeze as a list of items, where each item holds the 'Id' and the 'Name' from the 'Product' table as well as the properties relevant to that item, both from the 'Property' table (e.g. 'Name' of the property) as well as from the 'PropValue' table (particularly 'Value' holding the value for that property). I also need the items to be filtered by certain conditions, such as only 'Products' having some 'Property' with a 'Value' greater than 0 etc.
This can be done by creating a breeze query with 'expand' to retrieve data from all tables, such as:
var resultsQuery = new breeze.EntityQuery()
.from("Records")
.where(Predicate.and(andArray))
.expand("propValues,product,product.properties")
where the 'andArray' is an array of breeze Predicates each defined as something similar to:
Predicate.create("propValues", "any", Predicate.create("propertyId", "==", propID).and("value", ">", val)
and always having the following Predicate in the 'andArray' to retrieve only properties relevant to the product:
Predicate.create("productId", "==", productId)
using this approach, the code on the server side is:
[HttpGet]
[AllowAnonymous]
[EnableBreezeQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<Record> Records()
{
return _contextProvider.Context.Records;
}
It is important for me to use the caching mechanism breeze provides so that I can retrieve the data from the remote server only once.
The problem with the above approach is that I need to use paging: orderby, take and skip. For example I want the results ordered by the value of a certain property, divided in pages each having 5 items, and I only want the 2nd page. The above breeze query has no paging in it, and I cannot see how to add paging to this query.
Is it possible? How can I do that?
Is it possible to create a breeze query on the client side that will enable this? that would be best since I can do the filtering via breeze (using 'Predicate' as shown in the example above) and rely on breeze to cache the data.
Or do I need to create some code on the server side that will combine the various fields from the above 3 tables into a list of items, possibly as JSON objects, that are filtered on the server side and not on the client side? and will that list be cached?
If possible I will greatly appreciate a simple example code for the server and the client.
Thank you !

Related

Specify a Parent-Child relationship in EF Core without using identity columns

Specify a Parent-Child relationship in EF Core without using identity columns
What's an efficient way within Entity Framework Core 5 (C#) to work with the data in a hierarchial table that is linked via non-identity columns.
Here's my primary class:
public class ServiceProvider
{
[Key]
public int Id { get; set; }
public string ParentSPCode { get; set; }
public string SPCode { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ContactEmail { get; set; }
public string Status { get; set; }
}
The SPCode value is unique, which I enforce via C# code. The ParentSPCode may be null or must match an existing SPCode. Again I enforce this via C# code.
I want this table to hold any number of levels of parent-child (1 or more) records, as defined by ParentSPCode-SPCode pairs.
I can retrieve these records via a complex hierarchy of LINQ "joins", but I am thinking there must be a cleaner way by defining the appropriate EF Core 5 relationship.
If I was in SQL Server, I would do this via a CTE.
I want to be able to bring in the child records in a manner similar to .Include(q => q.ParentSPCode == x.SPCode).

Entity Framework: Mapping many-to-many

During my project in which I make some sort of webshop, I've came across a problem with my .NET backend where I use Entity Framework Code First with Fluent API.
In my frontend, Orders can be made and are passed to my backend where they end up as a Order object (code below). This Order contains a User and a Dictionary where Items and their ordered quantities are stored. My current goal is to store those Orders in my database to retrieve an Order history.
My understanding is that by itself, EF can't map a Dictionary. Being a student and having done mostly frontend, I don't really know how to tackle this.
I've tried converting that Dictionary to a List of ItemWrappers (containing both the Item and the amount) and making 2 tables: Order (OrderId, UserId) and OrderItem (OrderId, ItemId, Amount). This converts the Many-to-Many (Users to Items and Order is derived from the relation attribute) to a One-to-Many (Order to OrderItem).
I understand this from a purely database perspective. I could have managed if I were to write all the queries myself, but given that EF adds some abstraction to that, I am a bit lost. How do you suggest I do this?
The code is simplified to only show the class structure. Id is always generated on add and is used as primary key.
public class User {
public int Id { get; set; }
public string Name { get; set; }
}
public class Item {
public int Id { get; set; }
public string Name { get; set; }
}
public class Order {
public IList<OrderItemWrapper> ItemsList { get; set; }
//Either one of these 2
public Dictionary<Item, int> Items { get; set; }
public User User { get; set; }
public int Id { get; set; }
}
public class OrderItemWrapper {
public Item Item { get; set; }//Will use ItemId as key
public int Amount { get; set; }
}
Could you please go through my explanation for many-to-many relationship here.
Is the following tree of SchoolContext correct?

EF 6 Code First storing an entity Reference to specific child in a one of the collections on the entity

I have a domain model that has a collection of entities configured in the normal 1 to many relationship, however I want to store a reference to a specific item in that collection using a FK in this model
The list as defined in the model
public ICollection<SLWOUpdate> Updates { get; set; }
The reference to the specific item in the list
public int? SLWOUpdateId { get; set; }
[ForeignKey("SLWOUpdateId")]
public virtual SLWOUpdate LastUpdate { get; set; }
Of course the code is responsible for updating the specific item as opposed to having EF do it.
Is this kind of relationship configurable in EF?
The reason I want to do this is for querying filtering purposes as part of complex query that must execute as one statement
Ended up adding a new domain model to represent the LastUpdate which simply holds a primary key to this entity and a FK to the LastUpdate
New Domain Model to represent the Last Update
public virtual SLCurrentWOUpdate LastUpdate { get; set; }
public class SLCurrentWOUpdate
{
[Key]
public int SLWorkOrder_Id { get; set; }
public SLWorkOrder SLWorkOrder { get; set; }
public int? SLWOUpdateId { get; set; }
[ForeignKey("SLWOUpdateId")]
public SLWOUpdate SLWOUpdate { get; set; }
}
I can query this as part of a larger more complex set of predicates... I just have to reach into the model one reference deeper:
db.SLWorkOrders
.Where(t => t.TAutoDeclined != null && t.TClosedPendingPayment != null)
.Where(t => t.LastUpdate.SLWOUpdate.UpdateStatusType.SystemName == "CHANGE_PRIORITY");
Feels kind of hackish.. but it works..

Entity Framework with Proxy Creation and Lazy Loading disabled is still loading child objects

I'm having some issues with the Entity Framework using POCOs and I hope someone can tell me at a high level if the behaviour I'm seeing is expected or I need to dig deeper into why it's happening.
I have a class Customer and another CustomerType, so Customer has a property Type (of type CustomerType indicating the type) and CustomerType has property Customers which is a collection of Customers (All Customers that have that type) So these are basically the Navigation properties on both ends of an association, resulting in POCO code something like:
public partial class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public CustomerType Type { get; set; }
}
public partial class CustomerType
{
public CustomerType()
{
this.Customers = new HashSet<CustomerType>();
}
public int Id { get; set; }
public string TypeName { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
I have turned off Proxy creation and LazyLoading (i.e. both DbContext.Configuration.ProxyCreationEnabled=false and DbContext.Configuration.LazyLoadingEnabled=false) because they make Serialization a pain.
As expected when I get instances from the Customer set, the Type property on them is null by default.
But if I get instances from the Customer set with a .Include("Type") not only is it loading the Type properties, but it's also loading the children - i.e. the collection of Customers on each of these.
Is this expected?
It is semi expected. The Include extension affects the SQL that is run. Those CustomerTypes that ARE loaded (by virtue of being included in the Customer query) will be built into the object tree according to the CustomerType.ParentId column.
So if by some fluke both a parent and a child is loaded in the same query, the child will be stuffed into the parent.

MVC4 Stored Procedure returns results, but MVC shows the lookup field values are null

My proc returns all results but MVC is showing the lookups are null.
I have a VIEW where the "grid" for loop looks like this:
#foreach (var item in Model) {
<tr>
<td>#Html.ActionLink(item.Headline, "ViewDetails", "Advisory", new { id=item.AdvisoryId }, "")</td>
<td>#item.AdvisoryStartDate.ToShortDateString()</td>
<td>#item.AdvisoryType.AdvisoryType</td>
<td>#item.AdvisoryProvider.AdvisoryProvider</td>
<td>#item.AdvisoryCategory.AdvisoryCategory</td>
</tr>
}
The last three fields are lookups. I initially populated this with this controller call:
var advisories = db.Advisories.Include(i => i.AdvisoryType)
.Include(i => i.AdvisoryProvider)
.Include(i => i.AdvisoryCategory)
.OrderByDescending(i => i.AdvisoryStartDate);
ViewData["Advisories"] = advisories;
But I've now replaced that with this proc call (because I need to get "advisories" the user hasn't seen yet, so it's more complicated than the above, which is basically "get all"; I also need to query the DB by UserID whereas MVC only has User.Identity.Name):
var results = db.Database.SqlQuery<Advisory>("EXEC [ponzi].[uspUserAdvisories] {0}", User.Identity.Name).ToList();
ViewData["Advisories"] = results;
I know the proc returns all results (when I run it in SQL Server), but in MVC, when I mouse over "results", the AdvisoryCategoryID is filled in but AdvisoryCategory is null. Same with the other two lookups. I assume it's because AdvisoryCategoryID is in my Advisory model, but AdvisoryCategory is from the AdvisoryCategory model.
Here is the relevant part of the Advisory model:
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int AdvisoryId { get; set; }
public virtual int AdvisoryTypeID { get; set; }
public virtual AdvisoryTypes AdvisoryType { get; set; }
public virtual AdvisoryProviders AdvisoryProvider { get; set; }
public virtual int AdvisoryProviderID { get; set; }
public virtual AdvisoryCategories AdvisoryCategory { get; set; }
public virtual int AdvisoryCategoryID { get; set; }
How can I get these three lookup fields to show the data returned by the proc? Thanks.
I think it's about the eager loading of navigation properties (AdvisoryCategory etc), if I understand properly what you're trying to do...
If you're trying to load navigation properties - from your SQL query, SP - I don't think that'd work. That's the Include part of the normal linq statement above - and that generates
an more complex SQL to join in other table's properties etc. It gets
more complicated with more of it.
That doesn't work for code-first and even if it would requires special 'techniques' to get it to match.
See this link here for the confirmation Eager Load from Entity Framework SP
You can try setting it to lazy loading by default (virtual etc.) - and hope it'd load on first access. Also try different loading methods.
Or just explicitely load on demand sort of - see this link and Explicitly Loading.
Eager Load from Entity Framework SP
http://msdn.microsoft.com/en-US/data/jj574232
Eager loading in EntityFramework with DbContext.Database.SqlQuery
I found a solution: ViewModels. Relevant portion of the new AdvisoriesViewModel here (to replace my Advisories model):
public int AdvisoryTypeID { get; set; }
public string AdvisoryType { get; set; }
public string AdvisoryProvider { get; set; }
public int AdvisoryProviderID { get; set; }
public string AdvisoryCategory { get; set; }
public int AdvisoryCategoryID { get; set; }
Now I call my proc with this line, having replaced "Advisory" with "AdvisoryViewModel":
var advisories = db.Database.SqlQuery<AdvisoryViewModel>("EXEC [ponzi].[uspUserAdvisories] {0}", User.Identity.Name).ToList();
Since the returned data set has a model with the same fields, and which aren't relying on another model, it works.