How can I translate this linq query to a breeze query - breeze

I am in the process of learning Durandal and Breeze. And have choosing to create a SPA version of nerddinner.
The first query I need to execute is this:
public IEnumerable<JsonDinner> GetMostPopularDinners(int limit = 10)
{
var mostPopularDinners = from dinner in _db.Context.Dinners.Include("RSVPs")
where dinner.EventDate >= DateTime.Now
orderby dinner.RSVPs.Count descending
select dinner;
if (limit > 50 || limit <= 0)
limit = 10;
return mostPopularDinners.Take(limit).AsEnumerable().Select(JsonDinnerFromDinner);
}
I have started to write it with breeze but I am having trouble with this line " orderby dinner.RSVPs.Count descending" this is what I have so far.
var getMostPopularDinners = function() {
var query = EntityQuery
.from('dinners')
.where('eventDate', '>=', new Date(Date.now()))
.orderByDesc('RSVPs')
.expand('RSVPs');

Sorry, Breeze doesn't yet support ordering or filtering on an aggregate value ('count' in this case).
What you can do is turn this into a named query. (which is not well documented...) Basically this involves using the EntityQuery.withParameters method to pass additional parameters to any service method. So you can construct a query like the following that both passes parameters and still uses Breeze's IQueryable support.
EntityQuery.from("GetMostPopularDinners")
.withParameters({ EventDate: new Date(Date(now()) })
.take(10);
where your controller method would look something like this:
[HttpGet]
public IQueryable<Dinner> GetMostPopularDinners(DateTime eventDate) {
return _db.Context.Dinners.
.Where(dinner => dinner.EventDate >= eventDate)
.OrderByDescending(dinner => dinner.RSVPs.Count);
}
and ... you should not need to do an JsonDinnerFromDinner" call; Breeze handles this automatically.

Related

Search a collection of objects

I'm trying to search for a collection of potential nodes but unable to do it...
I have a product that has a relationship with many instances. I would like to query the DB and get all the instances that are in a list that i get from the user.
Cypher:
var query = _context
.Cypher
.Start(new
{
instance = startBitsList,
product = productNode.Reference,
})
.Match("(product)-[:HasInstanceRel]->(instance)")
.Return(instance => instance.Node<ProductInstance>());
The problem is startBitsList... I use StringBuilder to generate a query that contains all the instances I'm looking for:
private static string CreateStartBits(IEnumerable<string> instanceNames)
{
var sb = new StringBuilder();
sb.AppendFormat("node:'entity_Name_Index'(");
foreach (var id in productIds)
{
sb.AppendFormat("Name={0} OR ", id);
}
sb.Remove(sb.Length - 4, 4);
sb.Append(")");
var startBitsList = sb.ToString();
return startBitsList;
}
I get exceptions when trying to run this cypher...
Is there a better way to search for multiple items that are stored in the collection I get from the user?
OK, I think there are a couple of issues at play here, first I'm presuming you are using Neo4j 1.9 and not 2.0 - hence using the .Start.
Have you tried taking your query and running it in Neo4j? This should be your first port of call, typically it's easy to add a breakpoint on the .Results call and add a 'watch' for query.Query.DebugText.
However, I don't think you need to use the StartBits the way you are, I think you'd be better off filtering with a .Where as you already have the start point:
private static ICypherFluentQuery CreateWhereClause(ICypherFluentQuery query, ICollection<string> instanceNames)
{
query = query.Where((Instance instance) => instance.Name == instanceNames.First());
query = instanceNames.Skip(1).Aggregate(query, (current, localInstanceName) => current.OrWhere((Instance instance) => instance.Name == localInstanceName));
return query;
}
and your query becomes something like:
var prodReference = new NodeReference<Product>(2);
var query =
Client.Cypher
.ParserVersion(1, 9)
.Start(new {product = prodReference})
.Match("(product)-[:HasInstanceRel]->(instance)");
query = CreateWhereClause(query, new[] {"Inst2", "Inst1"});
var resultsQuery = query.Return(instance => instance.As<Node<Instance>>());
2 things of note
We're not using the indexes - there is no benefit to using them as you have the start point and traversing to the 'instances' is a simple process for Neo4j.
The 'CreateWhereClause' method will probably go wrong if you pass in an empty list :)
The nice thing about not using the indexes is that - because they are legacy - you are set up better for Neo4j 2.0

Asp.net MVC 4 Database Query returning sql query.

I am trying to query my database to get a specific data from my database. however when I convert the query to string it doesn't return the select value, instead it returns the whole SQL Query in a string. I am stumped on why this is happening
public ActionResult StudiedModules()
{
Model1 studiedModules = new Model1();
List<StudiedModulesModel> listModules = new List<StudiedModulesModel>();
using (EntityOne context = new EnitityOne())
{
foreach(var module in context.StudiedModules){
studiedModules.School = context.ModuleDatas.Where(p=>p.ModuleCode == module.ModuleCode).Select(u=>u.School).ToString();
studiedModules.Subject = context.ModuleDatas.Where(p=>p.ModuleCode == module.ModuleCode).Select(u=>u.Subject).ToString();
}
}
var data = listModules;
return View(data);
}
Calling ToString() on an Entity Framework Linq query like that will in fact return the SQL Query. So as it's written, your code is doing exactly what you wrote it to do.
If you want to select the first result from the IQueryable<T>, then you need to call First() before your ToString(). So, try changing
studiedModules.School = context.ModuleDatas.Where(p=>p.ModuleCode == module.ModuleCode).Select(u=>u.School).ToString();
studiedModules.Subject = context.ModuleDatas.Where(p=>p.ModuleCode == module.ModuleCode).Select(u=>u.Subject).ToString()
to
studiedModules.School = context.ModuleDatas.Where(p=>p.ModuleCode == module.ModuleCode).Select(u=>u.School).First().ToString();
studiedModules.Subject = context.ModuleDatas.Where(p=>p.ModuleCode == module.ModuleCode).Select(u=>u.Subject).First().ToString()
There are a whole lot more methods available depending on what you're trying to accomplish. If you want to get a list, use ToList(), or as Uroš Goljat pointed out, you can get a comma-separated list of values using the Aggregate( (a, b)=> a + ", " + b) method.
How about using Aggregate( (a, b)=> a + ", " + b) instead of ToString().
Regards,
Uros

Entity Framework 4: Best practices in searching?

I am developing a ASP.NET MVC 3 Application with EF4. I have about 50,000 entities and I'm querying them through LINQ to find what matches best with the given search criteria. There are multiple search criterion (up to about 12) and these are matcheon a step by step basis.
Ex: 50,000 students
Get the students within the age range -> A
From A, get the students who are male -> B
From B, get students who are enrolled to course CS101 -> C
What's the best way to achieve this?
step by step doesn't mean a lot for SQL and your linq query will be transformed to sql to query the db...
so
//I'm a IQueryable
var queryableStudents =
students.Where(m =>
m.Age > 10 &&
m.Gender == 'm' &&
m.CourseList.Any(x => x.Name == 'CS101');
//I'm no more an IQueryable
var result = queryableStudents.ToList();//the query will be sent to db and result returned.
But if search criteria are optional, you can do
//I'm a IQueryable
var queryableStudents = students;
if (searchCriteria.Age > 0)
//I'm still a IQueryable
queryableStudents = queryableStudents.Where(m => m.Age => searchCriteria.Age);
if (!String.IsNullOrEmpty(searchCriteria.Gender))
//I'm still a IQueryable
queryableStudents = queryableStudents.Where(m => m.Gender == searchCriteria.Gender);
//Now I'm no more an IQueryable
var result = queryableStudents.ToList()//the query will be sent to db and result returned.
If you want a "REAL" step by step, (showing results for each step), you can do
//I'm not an IQueryable
var a= students.Where(m => m.Age > 10).ToList();//you will get all students from your db who respect your first criterion, and then work on an IEnumerable, not an IQueryable.
//I'm not IQueryable
var b= a.Where(m => m.Gender == 'm');
//I'm not an IQueryable
var c= b.Where(m => m.CourseList.Any(x => x.Name == "CS101");
var A = from s in students
where ((s.age < max) && (s.age > min))
select s;
var B = from a in A
where (a.gender.Equals("Male"))
select a;
var C = from b in B
where (b.EnrolledCourses().Contains("CS101"))
select b;
Answering my own question - after some thought I figured out the most effiecient way of doing this is to use something like ElasticSearch to index the entries I want.
The given use case is not a very good one for LINQ/C#.

How do I use 2 include statements in a single MVC EF query?

I am trying to write a query that includes 2 joins.
1 StoryTemplate can have multiple Stories
1 Story can have multiple StoryDrafts
I am starting the query on the StoryDrafts object because that is where it's linked to the UserId.
I don't have a reference from the StoryDrafts object directly to the StoryTemplates object. How would I build this query properly?
public JsonResult Index(int userId)
{
return Json(
db.StoryDrafts
.Include("Story")
.Include("StoryTemplate")
.Where(d => d.UserId == userId)
,JsonRequestBehavior.AllowGet);
}
Thank you for any help.
Try to flatten your hierarchy if it works for you. Here is a sample, and you may want to customize it for your needs.
var result = from c in db.Customers
join o in db.Orders
on c equals o.Customers
select new
{
custid = c.CustomerID,
cname = c.CompanyName,
address = c.Address,
orderid = o.OrderID,
freight = o.Freight,
orderdate = o.OrderDate
};
If flattering does not meet your requirements then you need to use query that returns a Nested Group. Finally, look at the following link for more references - LINQ Query Expressions .

return custom json from LINQ select statement

A very new programmer to MVC, JSON & LINQ - I have created an ActionResult that returns a JSONResult:
var formhistory = from p in _formsRepository.ReturnedForms
where p.DateAdded >= DateTime.Now.Date.AddDays(-15) && p.DateAdded <= DateTime.Now.Date
group p by new {p.Centre, p.Form, p.DateAdded}
into g
select new {
g.Key.Centre,
g.Key.Form,
g.Key.DateAdded,
Total = g.Sum(p => p.Quantity)
};
return Json(formhistory, JsonRequestBehavior.AllowGet);
This gives me a nice JSON result set as follows:
[
{"Centre":"Centre1","Form":"Advice","DateAdded":"\/Date(1331856000000)\/","Total":1067},
{"Centre":"Centre1","Form":"Advice","DateAdded":"\/Date(1332460800000)\/","Total":808},
{"Centre":"Centre1","Form":"Advice","DateAdded":"\/Date(1333062000000)\/","Total":559},
{"Centre":"Centre1","Form":"Advice","DateAdded":"\/Date(1333666800000)\/","Total":1448}
]
My question is this: I'm trying to manipulate this JSON string so that instead of 2 key/value pairs for "Form" and "Total" I only have 1, i.e. "Form":"Total".
I realise this is probably a very basic question, but can anyone point me in the correct direction? (Apart from the door!)
select new {
g.Key.Centre,
//g.Key.Form,
g.Key.DateAdded,
Form = g.Sum(p => p.Quantity)
}
would give you a key "Form" whose value is the former "Total". Is that what you want?
Modify the select part in your linq query
select new {
g.Key.Centre,
g.Key.DateAdded,
NewField = String.Format("{0} - {1}",g.Key.Form,g.Sum(p => p.Quantity).ToString())
};
I think this will solve your purpose.

Resources