Should I use Collection or List or a regular array for Neo4jClient? - neo4jclient

I saw some code on StackOverflow of people using Collection<> for the Neo4jClient , but I couldnt find that in any namespace.
Furthermore, I couldnt find any mention of arrays or collections on the Github page. I'm brand new to Neo4jClient so excuse the newbie question (if it is so)
So, can someone tell me how to use an array in Neo4jClient with C# ? Include any namespaces if necessary.
I'm talking about serializing an array (e.g.: string [], List, or Collection<>)
Thanks

The final step of a Cypher query, .Results returns an IEnumerable. You can do anything you want with it. Each time you enumerate it, it will run the query against Neo4j.
For example,
var users = client.Cypher
.Match("(user:User)")
.Return(user => user.As<User>())
.Results;
foreach (var user in users) // The query actual runs here
{
}
This means that if you enumerated through it twice, you would actually run the query against the database twice:
For example,
var users = client.Cypher
.Match("(user:User)")
.Return(user => user.As<User>())
.Results;
foreach (var user in users) // The query actual runs here
{
}
foreach (var user in users) // And then it runs again here
{
}
Now, that's not usually what you want. You don't want to send the extra call to the database, and you don't want the risk of the data changing.
To get around this, people will often force it to enumerate early by using either ToArray() or ToList(). These come from System.Linq.
For example,
var users = client.Cypher
.Match("(user:User)")
.Return(user => user.As<User>())
.Results
.ToList(); // The query runs here now
foreach (var user in users) // This just enumerates the in-memory list
{
}
foreach (var user in users) // This just enumerates the in-memory list
{
}
None of this is specific to Neo4jClient: it's just how enumerables work in .NET.

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();

Partial Lookup Lists

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.

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();
}

How to limit the amount of data from an OData request?

I have a Users table of 76 users and UserGroups table.
Using MVC, OData, a generic repository and EF, I am trying to optimize data retrieval when filtering based on the user group:
/api/Users?$filter=USERGROUPS/any(usergroup: usergroup/ID eq 'Group1')
On the client side, I get the right number of users - 71 (as OData is filtering based on the result), however I want to limit the number of records being returned form the actual query - ie. I do not want to return all records then filter (not optimal for very large data sets).
My API controller method is as follows:
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<USER> Get()
{
var unitOfWork = new ATMS.Repository.UnitOfWork(_dbContext);
var users = unitOfWork.Repository<USER>()
.Query()
.Include(u => u.USERGROUPS)
.Get()
.OrderBy(order => order.USERNAME);
unitOfWork.Save(); // includes Dispose()
return users.AsQueryable();
}
I read in this post that:
Entity framework takes care of building dynamic query based on the
request.
However, using a SQL Server profiler, the query executed is requesting all the records, rather than a filtered query.
Adding a .Take() to the query does not accomplish the desired result, as we also need the actual number of records returned for paging purposes.
I was thinking of using the grabbing some properties through ODataQueryOptions, but that doesn't seem quite right either.
Is my implementation of Unit of Work and Repository incorrect, in relation to what I am trying to accomplish, and if so, how can this be corrected?
Simple - Just set the Page size for the Queryable atrribute [Queryable(PageSize=10)]
http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options#server-paging
If You'd tell the EF where to apply the options, it would work.
Like this :
//[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<USER> Get(ODataQueryOptions<USER> options)
{
var users = options.ApplyTo(_dbContext.Set<USER>()
.Query()
.Include(u => u.USERGROUPS)
.Get()
.OrderBy(order => order.USERNAME));
return users;
}
Your code didn't work, because it tried to apply the options onto the last line "users.AsQueryable()", so what actually happened, is that EF pull the FULL dataset, and then applied the query onto the last line (that being a in memory collection). And that's why You didn't see that "filter" not being passed to the SQL.
The mechanics are such, that EF tries to apply the Query, to the IQueryable collection that it finds in the code (there's still a question how does it find the correct line).

Using .where extension method causes duplicates (MVC-LINQ)

I am trying to create a partial view to display some data. My controller takes in a string itemID and performs a query based on that. When the partial view is called, it displays the same record over and over again.
Note: I changed the name of objects for security purposes.
[ChildActionOnly]
public ActionResult someAction(string itemID = "")
{
//Empty itemID
if(string.IsNullOrEmpty(itemID))
{
return RedirectToAction("Index", "Search");
}
var model = _db.someTable
.Where(r => r.itemID == itemID)
.OrderBy(r => r.col1)
.ThenBy(r => r.col2)
.Take(20);
return PartialView("_myView", model);
}
I have tried removing the OrderBy and ThenBy methods, but the result remain the same, (Order would not matter since they are duplicates...). When I remove the .Where method, it works as expected and displays 20 different records (though, not filtered by any means).
My view was created by Visual Studio using the List template. The view been proven working by removing the .Where method from the LINQ statement. Here are the important bits of the view:
#model IEnumerable<MyApp.Models.OperationData>
.
.
.
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.some column)
</td>
.
.
.
Any ideas as to what is wrong with this query?
EDIT: Tried the other LINQ syntax and ended up with the same results:
var model = from r in _db.someTable where r.itemID == itemID select r;
Winner winner chicken dinner!
Turns out the issue was with the mapping of model to table. The table I was working on has a composite key, which I didn't know about... After reading mipe34's bit about primary keys, I decided to do some investigation into the table structure. After discovering the composite keys, I added the mapping for the 2nd key and all works well.
This issue was extremely confusing since the SQL generated by LINQ worked perfectly fine when run in SQL Management Studio.
Thanks all!
Hit the breakpoint just after the model variable and see what SQL query is generated by LINQ - VS should display it for you. You can also try to execute the query (add .ToList() at the end of the query) to see the actual result, what is in the collection to distinguish if there is a problem in query or view.

Resources