问题
I want to use some external server-side logic to modify properties on the results of a query. To do this, I'll need to apply the Breeze query options, modify the result set, and return it.
I know essentially how I can apply OdataQueryOptions
to my query, but I don't want to miss out on all the things that BreezeJS does that Web Api's OData doesn't. For example, I want to keep inlineCount
.
How can I do this? Is there some way to hook into Breeze's query modifying code?
In case it matters, I'm using Entity Framework 6 and Web Api 2.
回答1:
Ok, I'm not sure if there's a better way (because this seems like a lot of work for what seems like it would be a common use case), but here's how I solved this.
I inherited from the QueryHelper
class to modify the PostExecuteQuery
method to execute a delegate.
public class ExtendedQueryHelper : QueryHelper
{
public ExtendedQueryHelperOptions Options { get; set; }
public ExtendedQueryHelper(ODataQuerySettings querySettings) : base(querySettings)
{}
public override IEnumerable PostExecuteQuery(IEnumerable queryResult)
{
if (Options != null && Options.PostExecuteQueryHandler != null)
{
return Options.PostExecuteQueryHandler(queryResult);
}
return base.PostExecuteQuery(queryResult);
}
}
The delegate is defined in a class called ExtendedQueryHelperOptions
public class ExtendedQueryHelperOptions
{
private const string EXTENDED_QUERY_HELPER_OPTIONS_KEY = "EXTENDED_QUERY_HELPER_OPTIONS_KEY";
public delegate IEnumerable PostExecuteQueryDelegate(IEnumerable queryResult);
public PostExecuteQueryDelegate PostExecuteQueryHandler { get; set; }
public void InjectIntoRequest(HttpRequestMessage request)
{
request.Properties.Add(EXTENDED_QUERY_HELPER_OPTIONS_KEY, this);
}
public static ExtendedQueryHelperOptions GetFromRequest(HttpRequestMessage request)
{
object options;
request.Properties.TryGetValue(EXTENDED_QUERY_HELPER_OPTIONS_KEY, out options);
return (ExtendedQueryHelperOptions)options;
}
}
In order to set these options, I had to inherit from BreezeQueryableAttribute
and inject these options when the QueryHelper
is being created:
public class ExtendedBreezeQueryableAttribute : BreezeQueryableAttribute
{
protected HttpRequestMessage Request { get; set; }
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
Request = actionContext.Request;
base.OnActionExecuting(actionContext);
}
protected override QueryHelper NewQueryHelper()
{
var queryHelper = new ExtendedQueryHelper(GetODataQuerySettings());
queryHelper.Options = ExtendedQueryHelperOptions.GetFromRequest(Request);
return queryHelper;
}
}
Now I can inject code to be run on the filtered results like this:
[BreezeController]
public class BreezeController : BaseController
{
//...
[HttpGet]
[ExtendedBreezeQueryable]
public IQueryable<Foo> Foos()
{
var options = new ExtendedQueryHelperOptions
{
PostExecuteQueryHandler = delegate(IEnumerable results) {
// This code will be run after the querying has been
// applied by Breeze
var foos = results.Cast<Foo>().ToList();
foreach (var foo in foos)
{
foo.ComputedProperty = ComputeSomething();
}
return foos;
}
};
// Inject these options into the Request, so the ExtendedBreezeQueryableAttribute
// can get to them later
options.InjectIntoRequest(Request);
return Db.Foos;
}
}
回答2:
I looked at the answer here and struggled with it, so came up with something simpler (but possibly far inferior).
Assuming you want to modify the entities which Breeze's query returns, then put a .ToList()
on the end of the query, modify the list items, and return them with 'list.AsQueryable()' Like this:
public IQueryable<CameraMetaData> CameraMetaDatas()
{
var query = ContextProvider.Context.Cameras;
var list = query.ToList();
foreach(var l in list)
{
//modify values
}
return list.AsQueryable();
}
来源:https://stackoverflow.com/questions/23794343/how-can-i-manually-execute-breeze-filters-in-web-api