Web API and queries with foreign keys - asp.net

I'm playing around with Web API, and I'm struggling a bit with creating queries to pull back data based on a filter. The classic example would be pulling back a list of items based on a foreign key.
Let's say I have the following entity:
Movie
======
id
directorId
categoryId
It would not be uncommon for me to build a DAO with the following methods:
MovieRepo.GetByDirector(int directoryId);
MovieRepo.GetByCategory(int category);
Recently, I have been using Linq and the Entity Framework to build retrieval methods that can be used by multiple calling clients, but whose returned list can filtered based on whatever criteria is passed to a filter
public IEnumerable<Movie> Get(MovieFilter filter){
IQueryable<Movie> query = _context.tblMovie;
if(!String.IsNullOrEmpty(filter.directorId))
query.Where(m => m.directoryId == filter.directorId);
if(!String.IsNullOrEmpty(filter.categoryId))
query.Where(m => m.categoryId == filter.categoryId);
return query.ToList();
}
The boilerplate Web API controller actions are:
IEnumerable<Movie> Get();
Movie Get(int id)
If I wanted to filter my query by directory or category with Web API, how exactly would I do it in a RESTful way? Given the way routing gets resolved, the following would be an ambiguous call:
IEnumerable<Movie> GetByCategory(int categoryId);
I haven't see much guidance on this, can someone provide some for me?
Regards,
Chris

One of the ways is to use OData protocol http://www.odata.org/docs/
There is also a library supporting OData filtering http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api, supporting querying over the IQueryable interface
It could be seen as a bit more complex, but you gain a lot. Parts of the OData standard :
$filter - Filters the results, based on a Boolean condition.
$select - which columns/properties should be selected
$inlinecount - Tells the server to include the total count of matching entities in the response. (Useful for server-side paging.)
$orderby - Sorts the results.
$skip - Skips the first n results.
$top - Returns only the first n the results.
Honestly, we are using the OData ... while not using the IQueryable and MS libraries. We just created own parser, supporting only limited stuff. But there is OData standard in place

Related

Azure Mobile Apps - Overriding the QueryAsync method with custom code in Table Controller

I would like to override the Query Async Method with some Custom code, so I can access an external api, get some data and then use this data to query the db tables to get the results, this should support all the default sync and paging features provided by the base method. I'm using the latest 5.0 DataSync library. Old versions returned a IQueryable so this was easy to do, but now it returns an action result. Is there any solution? Could not find any docs.
e.g. I get a set of guids from api. I query the db tables with these guids and get all the matching rows and return back to client.
I know how to override the method, call external api's, get data and query the db tables, but this provides me with a custom data format not the one that the query async gives by default with paging support.
The way to accomplish this is to create a new repository, swapping out the various CRUD elements with your own implementation. You can use the EntityTableRepository as an example. You will note that the "list" operation just returns an IQueryable, so you can do what you need to do and then return the updated IQueryable.

query ravendb from web api 2 and return one document

I want to do the following using Asp.net Web API 2 and RavenDB.
Send a string to RavenDB.
Lookup a document containing a field called UniqueString that contain the string i passed to RavenDB.
Return either the document that matched, or a "YES/NO a document with that string exists" - message.
I am completely new to NoSQL and RavenDB, so this has proven to be quite difficult :-) I hope someone can assist me, and i assume it is actually quite easy to do though i haven't been able to find any guides showing it.
This has nothing to do with WebAPI 2, but you can do what you ask for using RavenDb combined with WebAPI 2.
First you need to have an index (or let RavenDb auto create one for you) on the document and property/properties you want to be indexed. This index can be created from code like this:
public class MyDocument_ByUniqueString : AbstractIndexCreationTask<MyDocument>
{
public override string IndexName
{
get { return "MyDocumentIndex/ByUniqueString"; }
}
public MyDocument_ByUniqueString()
{
Map = documents => from doc in documents
select new
{
doc.UniqueString
};
}
}
or created in the RavenDb Studio:
from doc in docs.MyDocuments
select new {
doc.UniqueString
}
After that you can do an "advanced document query" (from a WebAPI 2 controller or similar in your case) on that index and pass in a Lucene wildcard:
using (var session = documentStore.OpenSession())
{
var result = session.Advanced
.DocumentQuery<MyDocument>("MyDocumentIndex/ByUniqueString")
.Where("UniqueString: *uniq*")
.ToList();
}
This query will return all documents that has a property "UniqueString" that contains the term "uniq". The document in my case looked like this:
{
"UniqueString": "This is my unique string"
}
Please note however that these kind of wildcards in Lucene might not be super performant as they might need to scan large amount of texts. In the RavenDB documentation there's even a warning aginst this:
Warning
RavenDB allows to search by using such queries but you have to be
aware that leading wildcards drastically slow down searches. Consider
if you really need to find substrings, most cases looking for words is
enough. There are also other alternatives for searching without
expensive wildcard matches, e.g. indexing a reversed version of text
field or creating a custom analyzer.
http://ravendb.net/docs/article-page/2.0/csharp/client-api/querying/static-indexes/searching
Hope this helps!
Get the WebApi endpoint working to collect your input. This is independent of RavenDB.
Using the RavenDB client, query the database using Linq or one of the other methods.
After the document is retrieved you may need to write some logic to return the expected result.
I skipped the step where the database gets populated with the data to query. I would leverage the RavenDB client tools as much as possible in your app vs trying to use the HTTP api.

ASP.NET OData query returns properties with empty values for virtual properties in code first models

I'm currently building a ASP.NET OData service which uses code first with EF5. When I do the query of a entity, it is returned as JSON along with empty values for the related entities.
I want the related entities attributes not to be included in the returned JSON for the entity query unless 'Include' is explicitly mentioned.
Is there a way to achieve this?
You have to enable lazy loading by setting the related members as virtual

RavenDB - building dynamic queries

I am building a simple CMS with .NET MVC and RavenDB and i need to filter pages with x amount of incoming parameters.
Example Page:
public class Page{
string Name
string Content
List<string> Tags
//etc...
}
In my pages controller i have this method and i want to get all the pages that have matching tags. they must be excluding filter so it is an AND condition that should be added
public ActionResult Index(List<string> tagFilters)
{
var pages = MyRavenSession.Query<Page>().Where( how to compare tagFilters List to pages Tags List? )
return View(pages);
}
I have been searching the internet for answers on this scenario and there should be others that have the same problem.
How should i solve this?
I read that predicatebuilder could not be translated to RavenDB LINQ queries.
I also read that you could build some kind of RavenDB lucene query but i cannot find any examples.
You can do that by using Session.Advanced.LuceneQuery() it allows fine grained dynamic query building

Entity Framework for Multi-tenant architecture - filterings single table by tenant ID

We are looking for a way of automatically filtering all CRUD operations by a tenant ID in Entity Framework.
The ideas we thought of were:
Using table valued user defined functions
Using stored procedures (but we don't really want to, as we're using an ORM to avoid doing so)
Some how modifying the templates used to generate the SQL to add a where clause on each statement.
Some how modifying the templates used to generate the LINQ in the controllers (we may use MVC).
Any tips?
-thanks
Alex.
Using table valued user defined functions
Table valued function are only available in .NET 4.5 Beta (and not available in code first). Using them will still not help you because you will have to use the function in every LINQ query so it is the same as using where clause.
Using stored procedures (but we don't really want to, as we're using an ORM to avoid doing so)
It can be useful for some special complex queries but generally it is not what you want.
Some how modifying the templates used to generate the SQL to add a where clause on each statement.
Too complex and on completely different level of abstraction.
Some how modifying the templates used to generate the LINQ in the controllers (we may use MVC).
Close to ideal solution. You simply need to wrap access to your entity set into some code which will look like:
public class MultiTenantAccess<T> where T : IMultitenant
{
private IDbSet<T> set;
...
public IQueryable<T> GetQuery(int tenantID)
{
return set.Where(e => e.TenantID == tenantID);
}
}
Sometimes this is core for something called Generic repository but it is really just a wrapper around EF set. You will always use GetQuery to query your data store instead of using DbSet directly.
you may also separate the tenants data into different databases
or into same database, but with different schemas? You can read more about this in an old MSDN article called "Multi-Tenant Data Architecture"

Resources