RIA Services Query - c#

I could use some help with a RIA services query that I have been struggling with for a bit now...
Person has a collection of DailyScore.
I want to be able to produce a query that is filtered on both Person and DailyScore.
DateTime start = ...
DateTime end = ...
var personQuery = context.GetPersonQuery().Skip.(10).Take(10)
var scoresQuery = from s in ctx.GetDailyScoresForPeriod(start, end)
where personQuery.Contains(s.Person)
select s;
...load the scoresQuery
What I would ideally want is the Person objects loaded with the appropriate DailyScores for the specified period.n We can assume all the 'includes' are in place too.
Is this possible in RIA Services? If so, can somebody give me the correct way of going about it, and if not are there any work arounds?
I feel like this is a simple request, so hopefully this is easy.
Thanks is advance,
Shane.
Also, can someone point me to a good online resource about the rules around using EntityQueries on the client side with RIA Services? I have struggled to find anything like this.

Actually, the query you are trying to do is not supported. You can't use Contains, Any, and similar constructs where you need to filter data in a collection.
In these scenarios you have two options:
Perform both queries separately, and then filter the data on the client. This approach has performance issues, because you are retrieving all the data from the server, and then filtering it out. In your case, you would something like this:
var personQuery = context.GetPersonQuery().Skip.(10).Take(10);
var scoresQuery = context.GetDailyScoresForPeriodQuery(start, end);
// Load both queries and then:
scores.Where(s => persons.Contains(s.Person))
Perform the query in the server. This approach is more performant, but you need to define a way to filter the persons in the same query. In your case, if you only want the persons whose ids fall in a specific range for example, you should add this method to your domain context (in the server):
IQueryable<DailyScore> GetDailyScoresForPeriodForPersons(DateTime start, DateTime end, int firstPerson, int lastPerson)
{
return context
.DailyScores
.Where(s => s.Start > start && s.End < end)
.Where(s => s.Person.ID >= firstPerson && s.Person.ID < lastPerson)
}
Then in your client, you would call it like this:
var scoresQuery = context.GetDailyScoresForPeriodForPersons(start, end, 10, 20)
Some resources:
Domain Context and Operations
Walkthrough: Adding Query Methods
RIA Services and relational data

Related

Fluent Linq and SQL Server

This may be a silly question, but I have fluent linq query that is pulling data off a DB, but, of course, it processes the data in memory, not on the DB.
Is there a means of taking a query (Say table.Where(t => t. id > 22)) and having it run as a db query (i.e. SELECT * FROM TABLE WHERE ID > 22).
I want to use the fluent style because I am building up the query from various places. I know I can make this specific query into query syntax, but my actual queries are more complex.
I have tried standard searches, but I suspect it is not going to be possible, as nothing comes up.
Yes using EF Core.
The code is not necessarily clear:
var getTableData = table.Where(base.whereSelection);
whereSelection.ForEach(w => getTableData = getTableData.Where(w));
At the moment, all of the Where Selections are Funcs - they could be converted to something else (like Expressions) if I knew that would make them run on the DB. The rest of the code is also building up this set of details programatically:
var selectedData = getTableData.Select(Convert);
var sortedTableData = GetSort(selectedData, Ordering);
var sorted = PickDataFrom(sortedTableData);
return CheckAndTake(sorted, pageSize);
Everything seems to work. Just in the wrong place.

Slow query performance on SQL Azure

I have built a document management system for my company. A desktop application connects to an ASP.Net Web API, hosted as an Azure Web App, which connects to an Azure SQL database.
As my database has become more populated, it is starting to slow down significantly so I need help with doing so query optimizations. Here is the Linq query that is currently causes me problems. Basically this query captures all the projects from the database and then populates a list in my desktop application
var projects = (from p in db.Projects.Include(c => c.ProjectType)
select new
{
ID = p.ID,
HasSubProjects = (db.Projects.Where(u => u.ParentProjectID == p.ID).Count() > 0) ? 1 : 0,
ParentProjectID = p.ParentProjectID,
Name = p.Name,
Description = p.Description,
DateLastEdited = p.DateLastEdited,
DateCreated = p.DateCreated,
ProjectTypeID = p.ProjectTypeID,
LastEditedByGoesby = p.LastEditedByGoesby,
ProjectComponentSecurityType = p.ProjectComponentSecurityType,
ClonedFrom = p.ClonedFrom,
DateAnyVersionLastEditedByUser = p.DateAnyVersionLastEditedByUser,
DateAnyVersionLastEdited = p.UserProjectActivityLookups
.OrderByDescending(u => u.LastActivityDate)
.Select(v => v.LastActivityDate)
.FirstOrDefault(),
// p.DateAnyVersionLastEdited,,
ProjectType = p.ProjectType
}).ToList()
.Select(x2 => new Project
{
ID = x2.ID,
HasSubProjects = x2.HasSubProjects,
ParentProjectID = x2.ParentProjectID,
Name = x2.Name,
Description = x2.Description,
DateLastEdited = x2.DateLastEdited,
DateCreated = x2.DateCreated,
ProjectTypeID = x2.ProjectTypeID,
LastEditedByGoesby = x2.LastEditedByGoesby,
ProjectComponentSecurityType = x2.ProjectComponentSecurityType,
ClonedFrom = x2.ClonedFrom,
DateAnyVersionLastEditedByUser = x2.DateAnyVersionLastEditedByUser,
DateAnyVersionLastEdited = x2.DateAnyVersionLastEdited,
ProjectType = x2.ProjectType
});
;
Any ideas on how to optimize this, avoid problems related to this query, create indexes better or using standard procedures etc would be helpful. I'm looking for direction on this specific query but also any guidance on how I can improve my performance on other queries and how to go about doing that.
Thanks.
Azure SQL database has several built in tools that provide query optimization help.
Query Store acts as "flight data recorder" for queries to get the data on query plans, execution times and to find most expensive queries. You can look at the execution statistics for your query above to see if there are any obvious problems.
Index advisor analyzes the historical resource usage and provides index advice and monitors the index usage
Various dynamic management views (DMVs) like dm_exec_query_stats provide query execution statistics information
MSDN article on azure sql database performance guidance provides a high level performance guidance information
Azure SQL database shares common codebase with SQL Server. So, most of the query optimization techniques used for SQL Server will also apply here. Bing/Google search on SQL Server query optimization will provide lots of pointers.
Srini Acharya
I think the best way for going about is to find out what sql query this code is generating. Then try to see what is the issue with that sql query and accordingly change your linq query.
Some things that you should look for:
ParentProjectID, check for the indexes and try to join instead of subquery.
Similarly check for DateAnyVersionLastEdited, since the query is going against the all user data. This could slow you down if this has a lot of data and bad indexes.
Last thing I would recommend to have a where clause depending upon the data you are retrieving.
So, if you are ultimately retrieving records in thousands, then try to restrict the count either by paging or by some other business condition.

linq to sql query with 2 dbml files

I have a object of MyFriendFollowStatus , for each friend I need information from 2 different databases, so I wrote something like this
db1Context FFdb = new db1Context();
db2Context EEdb = new db2Context();
foreach (fbFriendsFollowStatus a in fbids)
{
long ffID = FFdb.FFUsers.Where(x => x.FacebookID == a.fbid).FirstOrDefault().FFUserID;
a.ffID = ffID;
int status = EEdb.StatusTable(x => x.ffID == ffid).FirstOrDefault().Status;
a.Status = status;
}
this works, but it doesnt really seem right calling 2 databases - once each for each user , is there something built in LinqToSql that helps with something like this? or sometype of join I can use using 2 different databases?
Well, you can always limit your N+1 query problem to 3 queries - one to get users, one to get user's data form first database and one for the second database. Then connect all the results in memory - this will limit the connections to databases which should improve performance of your application.
I don't know if linq-to-sql or entity framework offers building model from different databases - this would pose some performance problems probably - like in includes or something, but I may simply not be aware of such features.
Sample code to do what you're trying to achieve would look something like that:
var facebookIds = fbFriendsFollowStatus.Select(a => a.fbid);
var FFUserIds= FFdb.FFUsers.Where(x => facebookIds.Contains(x.FacebookID)).Select(x => new { x.FacebookID, x.FFUserId)
var statuses = EEdb.StatusTable.Where(x => FFUserIds.Contains(x.ffID)).Select(x => new { x.ffID, x.Status})
And then some simple code to match results in memory - but that will be simple.
Please note that this code is sample - if I've mismatched some ids or something, but idea should be clear.

Modify linq query at runtime

Problem statement
Say I have a query which searches the names of people:
var result = (from person in container.people select person)
.Where(p => p.Name.Contains(some_criterion)
This will be translated to a SQL query containing the following like clause:
WHERE NAME LIKE '%some_criterion%'
This has some performance implications, as the database is unable to effectively use the index on the name column (index scan v.s. index seek if I'm not mistaken).
To remedy this, I can decide to just StartsWith() instead, generating a query using a like clause like:
WHERE NAME LIKE 'some_criterion%'
Which enables SQL server to use the index seek and delivering performance at the cost of some functionality.
I'd like to be able to provide the user with a choice: defaulting the behavior to use StartsWith, but if the user want the 'added flexibility' of searching using Contains(), than that should used.
What have I tried
I thought this to be trivial and went on and implemented an extension method on string. But of course, LINQ does not accept this and an exception is thrown.
Now, of course I can go about and use an if or switch statement and create a query for each of the cases, but I'd much rather solve this 'on a higher level' or more generically.
In short: using an if statement to differentiate between use cases isn't feasible due to the complexity of the real-life application. This would lead to alot of repetition and clutter. I'd really like to be able to encapsulate the varying behavior (Contains, StartsWith, EndsWith) somehow.
Question
Where should I look or what should I look for? Is this a case for composability with IQueryables? I'm quite puzzled!
Rather than overcomplicate things, how about just using an if statement?
var query = from person in container.people
select person;
if (userWantsStartsWith)
{
query = from p in query
where p.Name.Contains(some_criterion)
select p;
}
else
{
query = from p in query
where p.Name.StartsWith(some_criterion)
select p;
}
Update
If you really need something more complex try looking at LinqKit. It allows you to do the following.
var stringFunction = Lambda.Expression((string s1, string s2) => s1.Contains(s2));
if (userWantsStartsWith)
{
stringFunction = Lambda.Expression((string s1, string s2) => s1.StartsWith(s2));
}
var query = from p in container.people.AsExpandable()
where stringFunction.Invoke(p.Name, some_criterion)
select p;
I believe this fulfils your requirement of
I'd really like to be able to encapsulate the varying behavior
(Contains, StartsWith, EndsWith) somehow.
You can dynamically alter the query before enumerating it.
var query = container.people.AsQueryable();
if (contains)
{
query = query.Where(p => p.Name.Contains(filter));
}
else
{
query = query.Where(p => p.Name.StartsWith(filter));
}
Try dis:
var result = (from person in container.people select person)
.Where(p => some_bool_variable ? p.Name.Contains(some_criterium) : p.Name.StartsWith(some_criterium));
The real life queries are quite huge and unioned with several others. This, like my problem states, isn't te solution I'm looking for
Sinse your queries are huge: can't you just define stored procedure that handles everything and call it with specific to query parameters (probably several stored procedures that are called by main, e.g. one of em searches by Name, another - by Age, have different sort order and so on to keep code clear)?

Entity Framework Query filters implementation for best perfomance

As the title says, I´m using entity framework 4.0 for a financial application. I have a winform where I list all the cheques (checks) I have. But in that form, the user can specify some filters.
If the user does not apply any filter, I just can make the query like this:
lista_cheques = db.Cheque.Include("Operacion").Include("Cliente").ToList();
datagridview.Datasource = lista_cheques;
That is simple. But when it applies filters, the problem gets bigger.
As you see, the user can use filter to see cheques (checks) of a specific client, dates, bank, CUIT number, check state, etc.
Now, my question is related to performance in the queries.
I was thinking on doing the filters separeted, like this:
lista_cheques = db.Cheque.Include("Operacion").Include("Cliente").Where(x => x.fecha_deposito == fecha).ToList();
lista_cheques = lista_cheques.Where(x => x.banco.id_banco = banco).ToList();
lista_cheques = lista_cheques.Where(x => x.Operacion.Cliente.id_cliente = id_cliente).ToList();
Translation:
fecha is date
Operacion is a group of checks
Cliente is client.
In this way, I´m doing a query, then, a query from that query result, then a new query from that new result and that goes on.
I think this way might have a big performance issues. I know that SQL server optimize queries. So, if I´m doing fragmented queries, the optimizer is not working properly.
The other way I thought about but it´s very tedious, is to create one big query to handle every possible filter selection.
For example, the other example would be like this:
lista_cheques = db.Cheque.Include("Operacion").Include("Cliente").Where(x => x.fecha_deposito == fecha && x.banco.id_banco = banco && x.Operacion.Cliente.id_cliente = id_cliente).ToList();
The big problem is that I will need lots of combinations to be able to handle all the filter posibilities.
Ok guys, now, will I have performace issues in the first code example? I doing there one big query to the database, and then I´m doing the query in the list of objects (which I think will be faster). I´m pretty new to this ORM, and this listing will have to handle a lot of registries..
I somebody can give me some advice? I made pretty much a mess explaining, hope you can understand..
lista_cheques = db.Cheque.Include("Operacion").Include("Cliente").Where(x => x.fecha_deposito == fecha).ToList();
lista_cheques = lista_cheques.Where(x => x.banco.id_banco = banco).ToList();
lista_cheques = lista_cheques.Where(x => x.Operacion.Cliente.id_cliente = id_cliente).ToList();
Nearly perfect. Kill all those ToList and it is good.
The ToList means SQL is evaluated, so if all 3 flters trigger, 2 and 3 are evaluated in memory.
Kick the ToList away, and the different Where clauses get combined on the database.
Standard LINQ 101. Works like a charm and is always nice to see.
Then add as LAST line:
lista_cheques = lista_cheques.ToList ();

Categories

Resources