I'm trying to do something like:
var predicate = breeze.Predicate.create('columnName', breeze.FilterQueryOp.Contains, 'regexHere');
manager.executeQuery(entityQuery.From('tableName').where(predicate));
It all works fine when I try to search it "normal" way, but I'd like to include regex search that would work as sql LIKE operator. Mostly, I'm interested in how to make clause similar to sqls:
WHERE columnName LIKE '%abc%def%'
Is that possible with Breeze?
Sorry but [FilterQueryOp.Contains], FilterQueryOp.StartsWith and FilterQueryOp.EndsWith are the closest query operators to what you want. The OData spec that is used to construct a query url does not support regex based queries.
That said you can use EntityQuery.withParameters to do whatever you want with any parameters passed from a client. For example
// Client side
var query = EntityQuery.from("CustomersByRegex")
.withParameters({ regex: myRegex });
// Server side
[HttpGet]
public IQueryable<Customer> CustomersByRegex(string regex) {
// use the regex here against your customers collection
// and return the resulting customers;
}
You can also mix and match the two mechanisms. i.e. a regular breeze query with Filters and a 'withParamters' call.
Related
In my application, the query is being built by appending the first part(where clause) with the second part(order by) using a separate script like QueryBuilder.groovy and hence the order by part is prone to HQL injection which can't be sanitized by using Named Parameters. Therefore, I want to use findAll to retrieve a set of records by passing it a query and sorting and paging parameters separately. I saw an implementation like this:
domainClass.findAll(query,[namedParams],[max: 10, offset: 5])
When i passed sortColumn and sortDirection as named parameters, sortColumn worked fine but sortDirection didn't work. i need a way to either make sortDirection work as a named parameter or any other way which will combine 'sorting by direction' with the findAll result. Many people have suggested on various forums to just use the parameters directly as part of the query but it is unacceptable for my application as it will expose the query to HQL Injection.
Thanks in advance.
here is an example:
queryString = "FROM BookCatalog b WHERE b.bookNumber = :bookNumber"
this is passed to the QueryBuilder.groovy where something like this happens:
sort = "$params.sortColumn $params.sortDirection"
queryString.order(sort)
public void sort(String query){
this.query = this.query+" order by "+query
}
finally findAll retrieves the list of records:
def list = findAll(queryString,namedParams,queryParams)
so as the logic just appends the sorting parameters to the query string a potential hacker can do something like this:
bookCatalogView?offset=2&max=5&sortColumn=1,2,3 **or 1=1**
or
bookCatalogView?offset=2&max=5&sortColumn=1,2,3;**select * from whatever**
Don't concat strings, it's bad practice.
If you want to create complex queries, consider using createCriteria()
SomeDomainClass.createCriteria().list {
order("propName", "desc")
}
or, if you need more control, in the sessionFactory way:
query = sessionFactory.getCurrentSession().createCriteria(DomainClass.class)
query.addOrder(Order.asc("someField"))
query.addOrder(Order.desc("someotherField"))
I have two columns in my database table (dueDate & lateMinutes).
How do I create a Where predicate that adds lateMinutes to dueDate and compares the result to a given date (aGivenDate).
eg. .where(dueDate + lateMinutes > aGivenDate)
Any idea how to do this with a Breeze query where predicate?
Any help appreciated.
Regards,
Paul.
There is no standard query syntax supporting date arithmetic within breeze, so your best bet for this would be to use a named query with a parameter. i.e. So assuming that the name of your EntityType was say 'Schedule' something like this
On the client
var q = EntityQuery.from("SchedulesAfter")
.where(...) // this can be any valid where clause for the 'Schedule' type ( or can be omitted completely if you don't need additional query restrictions.
.withParameter( { givenDate: aGivenDate });
On the server
[HttpGet]
public IQueryable<Schedule> SchedulesAfter(DateTime givenDate) {
// This needs to return a valid IQueryable
// You will need to find the correct EF syntax to support your query here. You may need to use an EF function here instead.
return ContextProvider.Context.Schedules
.Where(s => DbFunctions.AddMinutes(s.DueDate ,s.LateMinutes) > givenDate);
}
In effect, you are calling a custom query method on the server with a parameter and then telling the server how to implement the query using this parameter.
I'm using OData with Entity Framework to select some records from a database. The records each have a path to a file with text content. In a single service call I'd like to be able to filter the DB records as well as filter the resulting objects based on the content of the files that the records point to. Because I can't mix LINQ to EF with LINQ to Objects, I believe the easiest way to accomplish this is to add an additional query parameter to the standard OData parameters that defines how to filter for file content after the standard odata filters have been applied.
Is looks like the entity query's "withParameters" method is the way to add a non-standard parameter but it doesn't seem to work with version 1.4.9 of breeze.
Am I doing something wrong or is there any intention to make this method work for the OData service provider?
As a workaround to this shortcoming, I've found that you can declare your entity to query with the parameters as part of the entity name, like so:
var entityId = 4;
var answerId = 6;
var entityToQuery = "MyEntity(EntityId=" + entityId + ",answerId=" + answerId + ")";
Then, build your breeze query:
var query = breeze.EntityQuery.from(entityToQuery);
This would map to an OData endpoint such as:
public IQueryable<MyEntity> GetMyEntity([FromODataUri] int entityId, [FromODataUri] int answerId)
{
}
No, you need to use the WebApi adapter. This is not a breeze shortcoming, it's a OData shortcoming because OData doesn't support this syntax.
However, the WebApi adapter does do everything you want and this is the Breeze default. Please see the docs for more information.
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).
I have the following model:
Products (DbSet<Product>)
ProductHasWidgets (DbSet<ProductHasWidget> many-to-many w/ payload)
Widgets (DbSet<Widget>)
I am getting stuck with querying across and/or from the many-to-many table and have two questions:
How do I write a breeze query to return all Products where:
Widget.IsActive == true
ProductHasWidgets.WidgetId == 1
You can't do that from a Breeze client yet because Breeze does not support the any keyword at this time.
You can write a service method to do the query on the server. The client can pass query parameters to that method using the BreezeJS withParameters query verb.
As of Breeze 1.4.6, Breeze now supports "any" and "all" queries. See: http://www.breezejs.com/documentation/query-examples
Depending on your model, this means that your query would look something like:
var predicate = breeze.Predicate.create("WidgetId", "==" 1)
.and("Widget.IsActive", "==", true);
var query = EntityQuery.from("Products")
.where("ProductHasWidgets", "any", predicate);