Partial Lookup Lists - breeze

I'm trying to limit the amount of data coming across when implementing Lookup Lists in Breeze.JS. The Lookup Lists sample uses queries that results in full objects but I would like to project the entities to fewer properties (e.g. primary key, foreign keys, and a descriptor property) and still have Breeze.JS recognize the entity type on the client. I know how to do the projections from the client to get partials but how would I do that with Lookup Lists (either from the client or the server Web API)?

You might satisfy your intentions with a custom JsonResultsAdapter.
You're probably wondering "What is a JsonResultsAdapter?"
That's what breeze uses to interpret the JSON arriving from the server. You can read about here and here.
Perhaps more helpful is to look at the adapter in the Web API dataservice and at the example adapter from the "Edmumds" sample.
The Edmunds sample demonstrates translating a JSON source that you don't control into breeze entities.
In this case, your JsonResultsAdapter would look at each node of JSON and say "this is a Foo, this is a Bar, and that one is a Baz". Accordingly, for each of these nodes it would return { entityType: "Foo" }, return { entityType: "Bar" }, and return { entityType: "Baz" }
Now breeze knows what to do and creates corresponding entities out of the Lookups payload.
Remember to mark these entities as partial, in the same way you would if you had made a projection query that targeted a single entity type.
Fortunately, the Lookups query returns the container object that holds the Foo, Bar, and Baz collections. So you can iterate over these and mark them partial right there in the query success callback.
Once you wrap your head around THAT ... you'll want to know how to put your custom JsonResultsAdapter to work in the Lookups query ... and ONLY in the Lookups query.
You can enlist that JsonResultsAdapter exclusively for your Lookups query with a using clause.
Here's an example:
var jsa = new breeze.JsonResultsAdapter({
name: 'myLookupsJsa',
visitNode: function() {...}
});
query = query.using(jsa);
Is this overkill? Would you be better off making three trips?
Only you will know. I would like to hear from you when you try it ... and give us your suggestions on how we might make this easier in a general way.

In the lookup lists example the controller action looks like this:
[HttpGet]
public object Lookups() // returns an object, not an IQueryable
{
var regions = _contextProvider.Context.Regions;
var territories = _contextProvider.Context.Territories;
var categories = _contextProvider.Context.Categories;
return new {regions, territories, categories};
}
You could reduce the footprint using a server-side projection like this:
[HttpGet]
public object Lookups() // returns an object, not an IQueryable
{
var regions = _contextProvider.Context.Regions
.Select(x => new { id = x.RegionId, name = x.RegionName });
var territories = _contextProvider.Context.Territories
.Select(x => new { id = x.TerritoryId, name = x.TerritoryName });
var categories = _contextProvider.Context.Categories
.Select(x => new { id = x.CategoryId, name = x.CategoryName });
return new {regions, territories, categories};
}
This approach does not answer this part of your question:
and still have Breeze.JS recognize the entity type on the client
Not sure what the solution or use case is for this piece.

Related

BreezeJS count of expanded entities

This is using BreezeJS and a Breeze controller through to an EF provider. I have a couple of related Entities, lets call them Customer, which has a Navigation Property called Orders which links to a set of Order Entities for that customer.
What I'd like to display on the UI is a summary of Order Counts for a set of customers who match a partial name search. I can do this through returning all the Order objects, but they're quite large objects and I don't really want to return 100's of them when I don't have to. The inlineCount() method seems to always give the count of the top-level entity (Customer) rather than of the sub-Entities, no matter where I place it in the statement.
var predicate = breeze.Predicate.create('displayName', 'contains', partialName);
return this.entityQuery.from('Customers')
.where(predicate)
.orderBy('displayName')
.using(this.manager)
.expand('Orders')
.execute();
The documentation suggests that you can chain the expand in some way, but I have yet to find a syntax which is valid.
Ideally, I'd like to apply a where to the Orders by a property on Order called Status of say 0 (incomplete) and then give me just the count of those matching Orders. ie, return me all the Customer entities, but have a matching order count for each (rather than the whole list of Order objects and filter client-side).
Would appreciate any pointers in the right direction if it's possible to achieve. My current thinking is that I'll have to create a custom method on the server-side controller and do the work there, but before I make assumptions about what OData can support, I thought I'd check here for some confirmation.
So far, this is my best approach (maybe someone can correct me if there's a better way).
On the server, add this method:
public IQueryable<object> CustomerSummaries()
{
return Context.Customers.Select(p => new
{
Customer = p,
ActiveOrderCount = p.Orders.Count(o => o.Status == 1)
});
}
Then on the client end:
var predicate = breeze.Predicate.create('customer.displayName', 'contains', partialName);
return this.entityQuery.from('CustomerSummaries')
.where(predicate)
.using(this.manager)
.execute();

Performant loading of collections of Model Data using Linq in MVC

We have controllers that read Entities with certain criteria and return a set of view models containing the data to the view. The view uses a Kendo Grid, but I don't think that makes a particular difference.
In each case, we have a Linq Query that gets the overall collection of entity rows and then a foreach loop that creates a model from each row.
Each entity has certain look ups as follows:
those with a 1:1 relationship, e.g. Assigned to (via a foreign key to a single person)
those with a 1:many relationship e.g. copy parties (to 0:many people - there are not many of these)
counts of other relationships (e.g. the number of linked orders)
any (e.g. whether any history exists)
If we do these in the model creation, the performance is not good as the queries must be run separately for each and every row.
We have also tried using includes to eager load the related entities but once you get more than two, this starts to deteriorate too.
I have seen that compiled queries and LoadProperty may be an option and I am particularly interested in the latter.
It would be great to understand best practice in these situations, so I can direct my investigations.
Thanks,
Chris.
Edit - sample code added. However, I'm looking for best practice.
public JsonResult ReadUsersEvents([DataSourceRequest]DataSourceRequest request, Guid userID)
{
var diaryEventModels = new List<DiaryEventModel>();
var events = UnitOfWork.EventRepository.All().Where(e => e.UserID == userID);
foreach (var eventItem in events)
{
var diaryModel = new DiaryEventModel(eventItem);
diaryEventModels.Add(diaryModel);
}
var result = diaryEventModels.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
public DiaryEventModel(Event eventItem) {
// Regular property from Entity examples - no issue here as data retrived simply in original query
ID = eventItem.ID;
Start = eventItem.StartDateTime;
End = eventItem.EndDateTime;
EventDescription = eventItem.Description;
// One to one looked up Property example
eventModel.Creator = eventItem.Location.FullName;
// Calculation example based on 0 to many looked up properties, also use .Any in some cases
// This is a simplified example
eventModel.AttendeeCount = eventItem.EventAttendees.Count();
// 0 to Many looked up properties
EventAttendees = eventItem.EventAttendees.Select(e => new SelectListItem
{
Text = e.Person.FullName,
Value = e.Person.ID.ToString()
}).ToList();
}

Implementing $select with WebApi and ODataQueryOptions

I'm trying to implement some OData functionaility with a custom DAL using ODataQueryOptions.
My DAL uses design time generated typed data tables. By intercepting the SelectExpand property of ODataQueryOptions i can get our DAL to only load the columns required.
How do i then return just the data required.
I am currently tipping the data from our type datatables into a ListOf some typed data tranfer objects but then end up with lots of null data from the columns which aren't required.
I feel like i should be able do some LINQ query to select the just the columns I need straight from the typed datatable bypassing using typed DTOs altogether. Is this possible?
You need to do the same thing that SelectExpandQueryOption.ApplyTo does.
1) Optimize the query to the backend. Instead of getting the whole entity from the database, get only the properties the client asked for and wrap that result in an IEdmEntityObject. Return the collection as EdmEntityObjectCollection. This step is optional. You could choose to ignore this step and return IQueryable and still get $select to work.
2) Tell the OData formatter to serialize only the requested fields. This can be done by stuffing the SelectExpandClause on the Request object using the extension method Request.SetSelectExpandClause.
public class CustomersController : ODataController
{
public IEnumerable<Customer> Get(ODataQueryOptions<Customer> query)
{
Customer[] customers = new[] { new Customer { ID = 42, Name = "Raghu" } };
// Apply query
var result = customers;
// set the SelectExpandClause on the request to hint the odata formatter to
// select/expand only the fields mentioned in the SelectExpandClause.
if (query.SelectExpand != null)
{
Request.SetSelectExpandClause(query.SelectExpand.SelectExpandClause);
}
return result;
}
}

MVC and Entity Framework Key

I am new to MVC and EF and am having a heck of a time getting an EF query to work, specifically with the EF key="". After adding some test code, the error being returned here is 'The name idAddress does not exist in the current context'. There is a primary key on the Address table named idAddress - identty int
I have read through many suggestions on the site and can't get past this.
private motion_care_360Entities db = new motion_care_360Entities();
public ActionResult GetItems(GridParams g)
{
var list = db.Addresses.Include("AddressCountry").Include("AddressState").Include("AddressType").AsQueryable();
var list1 = list.OrderBy(o => idAddress).ToList();
var l1 = list1[0].AddressState.State;
return Json(new GridModelBuilder<Address>(list, g)
{
Key = "idAddress", // needed when using Entity Framework, usually it's Id
// If you're using EF, it's needed so that the data will be ordered by it before paging it
Map = o => new
{
AddressTypeType = o.AddressType.Type,
AddressStateState = o.AddressState.State,
AddressCountryCountry = o.AddressCountry.Country,
o.City,
}
}.Build());
}
}
That would need to be list.OrderBy(o => o.idAddress).ToList();
You need to specify that it's by the idAddress of the object (i.e. o from your lambda expression) itself.
You're actually confused about a lot of things. First, the issue you claim you have has nothing to do with either MVC or EF. It has to do with whatever GridModelBuilder is, and since that's not a part of MVC, you must be using some third party control for that.
Second, I'm guessing (since I don't know what third party control you're using) that Key is used when using GroupBy, not when using OrderBy. OrderBy does not have a key, but GroupBy does. But it's hard to know, since you seem to think that third party tools are part of the framework.
Third, your OrderBy is assigned to list1, which you never use. You use list, which is unordered.
Fourth, you don't need AsQueryable as it's already a Queryable.

Entity Framework testing with IRepository - problem with lazy loading

I am refactoring an MVC project to make it testable. Currently the Controller uses the Entity Framework's context objects directly to ask for the required data. I started abstract this and it just doesn't work. Eventually I have an IService and an IRepository abstraction, but to describe the problem let's just look at the IRepository. Many people advise an interface with functions which return some of these: IQueriable<...>, IEnumerable<...>, IList<...>, SomeEntityObject, SomeDTO. Then when one wants to test the service layer they can implement the interface with a class which doesn't go to the database to return these.
Problem: Using linq to entities I have lazy (deferred) loading in my toolset. This is actually very useful, because my controller action functions know which data they need for the view and I didn't ask for more than required. However linq to anythingelse doesn't have lazy loading. So when my IRepository functions return any of the above mentioned things I lose lazy loading. I extended my interface with functions like "GetAnything" and "GetAnythingDeep" but it's not enough: it has to be much more fine-grained. Which would result about 5-6 functions for the same type of object, depending on the properties I want to get in the result. Maybe could be a general function with some "include properties" parameter, but I don't like that too.
Eventually atm I think if I want to make it testable that will result either much less efficient or much more complicated code. Sounds not right.
Btw I was thinking about to change the data source behind the entity model to either xml or some object data soruce, and so I could keep the linq to entities. I found that it's not supported out of the box... which is also sad: this means that entity framework means database source - not a really useful abstraction.
Specific example:
Entity objects:
Article, Language, Person. Relations: Article can have 1-N languages, and one Person (publisher).
ViewModel object:
ArticleDeepViewModel: Contains all the properties of the article, including the languages and the Name of the Person (it's for view the article, so no need for the other properties of the person).
Controller action which will return this view should get the data from somewhere.
Code before modifications:
using (var context = new Entities.Articles())
{
var article = (from a in context.Articles.Include("Languages")
where a.ID == ID
select new ViewArticleViewModel()
{
ID = a.ID,
Headline = a.Headline,
Summary = a.Summary,
Body = a.Body,
CreatedBy = a.CreatedByEntity.Name,
CreatedDate = a.CreatedDate,
Languages = (from l in context.Languages select new ViewLanguagesViewModel() { ID = l.ID, Name = l.Name, Selected = a.Languages.Contains(l) })}).Single();
this.ViewData.Model = article;
}
return View();
Code after modifications could be something like:
var article = ArticleService.GetArticleDeep(ID);
var viewModel = /* mapping */
this.ViewData.Model = viewModel;
return View();
Problem is that GetArticleDeep should return an Article object with Languages included and the entire Person object included (it shouldn't know that the viewmodel needs just the Name of the Person). Also I have so far 3 different viewmodels for an article. For example if someone wants to see the list of articles, then it's unnecessary to get the languages, the body and some other properties, however it might be useful to get the Name of the publisher (which is in the deep). Before "testable" code the controller actions could just contain the linq to entities query and get whichever data they need using lazy loading, Include function, using subqueries, referencing foreign properties (Publisher.Name) ... So there is no unnecessary query to the database and no unnecessary data transferred from the database.
What should be the IService or IRepository interface provide to get the 3-4 different level of Article objects or sometimes list of these objects?
Not sure if you are planning to stick with lazy loading, but if you want a flexible way to integrate eager loading into your repository and service layers first check out this article:
http://blogs.msdn.com/b/alexj/archive/2009/07/25/tip-28-how-to-implement-include-strategies.aspx
He basically gives you a way to build a strongly-typed include strategy like this:
var strategy = new IncludeStrategy<Article>();
strategy.Include(a => a.Author);
Which can then be passed into a general method on your repository or service layers. This way you don't have to have a separate method for each circumstance (i.e. your GetArticleDeep method).
Here is an example repository method using the above include strategy:
public IQueryable<Article> Find(Expression<Func<Article, bool>> criteria, IncludeStrategy<Article> includes)
{
var query = includes.ApplyTo(context.Articles).Where(criteria);
return query;
}

Resources