I'm trying out BreezeJS
. There is a requirement that I can use .expand
in the client side code, but based on the role
of the user, the server side will not return all the records for the .expand
requested type. I tried to create a custom BreezeQueryable
attribute and override a method to completely filter out the extra data first just to try. But it threw an exception.
I don't see any entry point where I can do that on the server side.
Please guide me in the right direction, or let me know if that's not possible. I only have access to generic IQueryable
, how do I perform queries on this?
Here's some sample code:
Server:
[BreezeController]
[EnableCors("*", "*", "*")]
public class MyDataController : ApiController
{
readonly EFContextProvider<MyDbContext> _contextProvider;
public MyDataController()
{
_contextProvider = new EFContextProvider<MyDbContext>();
_contextProvider.Context.Configuration.ProxyCreationEnabled = false;
_contextProvider.Context.Configuration.LazyLoadingEnabled = false;
}
// GET api/<controller>
//Trying to use a custom attribute to filter data here
[CustomBreezeQueryable(AllowedQueryOptions = AllowedQueryOptions.All)]
[HttpGet]
public IQueryable<MyData> GetAllData()
{
var data = _contextProvider.Context.MyData;
return data;
}
}
public class CustomBreezeQueryableAttribute : BreezeQueryableAttribute
{
public override IQueryable ApplyQuery(IQueryable queryable,
ODataQueryOptions queryOptions)
{
var data = base.ApplyQuery(queryable, queryOptions);
//trying to filter out MyDataHistory for MyData for testing,
//it throws exception
//data = data.OfType<MyDataHistory>();
return data;
}
}
Client side:
breeze.EntityQuery.from("GetAllData").expand('MyDataHistory')
.using(this.manager)
.execute()
.then((data) => {
console.log(data.results[0]);
def.resolve(data.results);
});
This is the exception
I get when using OfType
, and I would like to filter, not use that anyways.
{"DbOfTypeExpression requires an expression argument with a polymorphic result type that is compatible with the type argument."}
Not entirely sure I understand your issue, but you can perform the 'expand' on the server side via an EF 'Include' like that shown below:
[HttpGet]
public IQueryable<Customer> CustomersAndOrders() {
var custs = ContextProvider.Context.Customers.Include("Orders");
return custs;
}
Which will return 'Customer' objects each with its 'Orders' property fully populated and loading into the Breeze cache.
If you want to actually suppress 'expansion' on the server for a given resource name you can use the the [BreezeQueryableAttribute]. Note that AllowedQueryOptions.Expand is omitted from the list of supported operations in the example below.
[HttpGet]
[BreezeQueryable(AllowedQueryOptions = AllowedQueryOptions.Filter | AllowedQueryOptions.Skip | AllowedQueryOptions.Top | AllowedQueryOptions.OrderBy)]
public IQueryable<Employee> Employees() {
return ContextProvider.Context.Employees;
}
The [BreezeQueryableAttribute] supports the same parameters as Microsoft's [QueryableAttribute] described here: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options
The other option if you want to actually restrict/filter what gets expanded can only be done by performing the filtering expansion yourself, possibly with the help of parameters passed into the method via 'withParameters' (This is because EF does not yet support filtering on 'Includes'. I have not tested the example below but the general idea should work.
[HttpGet]
public IQueryable<Employee> Employees(double minWeight) {
var emps = ContextProvider.Context.Employees.Include("Orders").ToList();
// remove selected orders from what gets returned to the client.
emps.ForEach(emp => {
var ordersToRemove = emp.Orders.Where(o => o.Freight < minWeight).ToList();
ordersToRemove.ForEach(o => emp.Orders.Remove(o));
});
return emps;
}
来源:https://stackoverflow.com/questions/22491332/breeze-filtering-expand-on-server-side