Linq-to-SQL statement issue - c#

I am basically looking to bind a search query to a gridview which is nice, but this must be done by a users input query (sort of like a search function). I can get single values and rows returned, but how would I get it to search all columns in my database for the inputted values and return it?
My code so far is:
Void SearchFunction()
{
TiamoDataContext context = new TiamoDataContext();
var search from p in context.UserProfiles
where p.DanceType == UserSearchString
select p;
UserSearchGrid.DataSource = search;
UserSearchGrid.DataBind();
}
I tried p.equals but am pretty sure thats not the way to go about it.

It looks like your query sytax is a little off. It should look like:
var search = from p in context.UserProfiles
where p.DanceType == UserSearchString
select p;
Since you're trying to query multiple columns, you're going to have to chain the names of the columns you're looking at with or's:
var search = from p in context.UserProfiles
where p.DanceType == UserSearchString ||
p.Name == UserSearchString ||
p.SomeOtherStringColumn == UserSearchString
select p;
Or if you want to use the Lambda syntax:
var search = context.UserProfiles.Where(p => p.DanceType == UserSearchString ||
p.Name == UserSearchString ||
p.SomeOtherStringColumn == UserSearchString);
Keep in mind that using either of these methods implies that p.DanceType is a string type.

If you want it to search every column in the table, then you have to tell it to search every column in the table.
var search =
from p in context.UserProfiles
where
p.DanceType == UserSearchString ||
p.Foo == UserSearchString ||
p.Bar == UserSearchString
select p;
That's all there is to it. There's no magic operator that will do it automatically (there can't be - some columns might not even be strings).
Keep in mind that this will likely be very slow, as the query optimizer won't be able to pick a single index that can handle this entire query.
As an aside, this "search" only tests for pure equality. You might want to use StartsWith or Contains for a prefix or substring search, respectively.

Related

Combining LINQ queries in LINQ to CRM causes problems?

Something weird is going on.
If I do this:
var allAccountsQuery = from acc in baseQ
where
//high potential check - 1, 2, 3
(acc.mcpl_potencjal_klienta == 1 || acc.mcpl_potencjal_klienta == 2 || acc.mcpl_potencjal_klienta == 3) &&
//directors block check
((acc.mcpl_blokada_dyrektorska == true && acc.mcpl_blokada_do <= date) || acc.mcpl_blokada_dyrektorska == false || acc.mcpl_blokada_dyrektorska == null) &&
//sack assign date check
(acc.mcpl_dataprzypisaniazworka == null || acc.mcpl_dataprzypisaniazworka < date) &&
//owner change check
(acc.mcpl_datazmianywasciciela == null || acc.mcpl_datazmianywasciciela < date) &&
//creation date check
//TODO:For testing!
//(acc.mcpl_data_utworzenia_test < date)
(acc.createdon < date)
select acc;
var joinQuery = from acc in allAccountsQuery
join opp in ctx.opportunityopportunities on acc.accountid equals opp.customerid.Value
select new
{
Account = acc,
Opportunity = opp
};
Plugins.Common.XrmHelper.ClearCache("account");
var joinResult = joinQuery.ToList();
Then I'll get an unknown platform error when executing this query. I need to copy-paste the WHOLE where clause from allAccountsQuery to the joinQuery and use baseQ again, and then it works.
What's going on here? I thought you can safely join LINQ queries as long as you're not doing any unsupported operations.
PS. The STRANGEST part is that the pasted code WILL work with slightly different where conditions.
PPS. baseQ is just an even simpler where query, much like the allAccountsQuery.
Maybe is not the answer but as I can't leave a comment and no one has answer I think this could help.
Why you don't do the join in the first query? As from I know the LINQ CRM queries have problems joining tables when in the clause WHERE we have the OR Predicate, and not when we try to select from different tables, I think for you query should work. I have one post explaining what I learned.
Linq-to-CRM has a limited set of supported operations compared to other providers life EF or Linq-to-SQL.
You may have better success hydrating one or both of the two queries. Since your account query has a where clause try hydrating it:
var joinQuery = from acc in allAccountsQuery.ToList() // call ToList() to hydrate the query
join opp in ctx.opportunityopportunities
on acc.accountid equals opp.customerid.Value
select new
{
Account = acc,
Opportunity = opp
};
If you have a LARGE number of Opportunities you may want to try and filter that query based on the accounts returned from the first query before doing the Join.

C# SQL To Linq - Where Clause with multiple variables Comparison (var1+var2) !=(var1+var2)

I have these working in sql for large data set working great. However I'm having hard time converting to linq-I'm new to linq
Select * from table1 t1, table2 t2 where (t1.RoleId+t1.UserId)!=(t2.RoleId+t2.UserId).
On a side note, when the two variables are separated, I get undesired results.
Meaning the following: where (t1.RoleId != t2.RoleId && t1.UserId != t2.UserId)
In c# I have two anonymous lists. The last linq statement works great till nulls come into the picture. Nothing returns. I even thought of using a left join with no success.
So how would you tackle the above query with anonymous type lists?
Linq statments I have so far
var roleUserList =
(
from rls in roleResouceList
join user in userResourceList
on rls.FullResource.ToUpper() equals user.FullResource.ToUpper()
orderby rls.RoleID, user.UserID, rls.Res1, rls.Res2, rls.Res3
select new
{
RoleID = rls.RoleID,
UserID = user.UserID,
ServerId = rls.ServerID,
FullResource = rls.FullResource,
RlsRes1 = rls.Res1,
RlsRes2 = rls.Res2,
RlsRes3 = rls.Res3
}).Distinct().ToList();
var missingRoleUserList =
(
from rls in rlsCount
join usr in usrCount
on rls.Res1 equals usr.Res1
where rls.Total > usr.Total
select new
{
UserID = usr.UsrID,
RoleID = rls.RoleID
}).Distinct().ToList();
List<string> outputRoleUserList =
(
from rls in roleUserList
from mis in missingRoleUserList
where (rls.RoleID + rls.UserID) != (mis.RoleID +mis.UserID)
select rls.UserID + ",\"" + rls.RoleID
).DefaultIfEmpty().Distinct().ToList();
I'm not entirely certain that this is what you're looking for, but I'm going to give it a shot:
Try chaining your where clauses in Linq to SQL, and you may get a better result:
List<string> outputRoleUserList =
from rls in roleUserList
from mis in missingRoleUserList
where rls.RoleID != mis.RoleID
where rls.UserID != mis.UserID
select rls.UserID + ",\"" + rls.RoleID
This will actually generate SQL as follows:
rls.RoleId != mis.UserID AND rls.UserId != mis.UserID
However, you have already forced execution on roleUserList and missingRoleUserList, so what you're using in the third Linq statement is not really Linq to SQL but rather Linq to Objects, if I'm reading this correctly.
I'd be curious to see some additional information or clarification and then maybe I'll understand better what's going on!
EDIT: I realized another possibility, it's possible that the object.UserID or object.RoleID is throwing an internal NullPointerException and failing out because one of those values came back null. You could possibly solve this with the following:
List<string> outputRoleUserLIst2=roleUserList
.Where(x => x != null && x.UserID != null && x.RoleID != null && missingRoleUserList
.Where(y => y != null && y.UserID != null && y.RoleID != null && y.RoleID!=x.RoleID && y.UserID!=x.UserID)
.FirstOrDefault()!=null)
.Select(x => x.UserID + ",\"" + x.RoleID).Distinct().ToList();
This is not pretty, and this is the other Linq syntax (with which I am more comfortable) but hopefully you understand what I am going for here. I'd be curious to know what would happen if you dropped this into your program (If I've guessed all of your meanings correctly!). I'll look back in a bit to see if you have added any information!

Possible to do this in linq?

I am wondering if something like this could be done(of course what I have written does not work but that's what I am essentially trying to achieve) .
var test = u.Owner;
a.Table.Where(u => test == true)
I have a linq query that I want to reuse(basically I got a query that I use 5 times) and the only thing that changes is what I am comparing against.
So in the above u.Owner is compared against true. In another query it would look the same but instead of u.Owner I might have u.Add == true or u.Edd == true.
So is there a way I can sort of reuse what I have. Of course in my code the query is a bit longer but I just shortened down.
Edit
Basically the whole query
List<Permission> clearence = user.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner)).ToList();
permissionNeeded == Enum
So my orignal way of doing it was u.Permission.Name == permissionNeeded so I compared the enum value to a string.
Now my db model has change and I need to check against 5 different permissions separately that are bools and not strings.
u.Add = true || u.Owner == true;
u.Edit = true || u.Owner == true;
u.Delete= true || u.Owner == true;
u.View= true || u.Owner == true;
Thats all changes for the entire query so that's why I am trying to make it into one query(just like I had it before).
So I am thinking of having a switch statement. The method still takes in a permissionNeeded(enum) I then go through and determine what clause I need and some how insert it into the query.
switch(PermssionNeeded)
{
case PermissionTypes.Add:
u.Add;
break;
// all other cases here.
}
Take advantage of the fact that Where can have any function taking type Table as a parameter and returning a boolean to create a function like:
public IQueryable<Table> QueryTables(Func<Table, bool> testFunction)
{
return a.Table.Where(testFunction).AsQueryable<Table>();
}
Edit: (in addition to edit to add AsQueryable above, which I earlier forgot)
If all you want to do is vary the boolean field used in the test, and you don't want to have to specify an entire function (which you're about to find out is much easier), you would need to use some reflection:
using System.Reflection;
public IQueryable<Table> QueryTables(PropertyInfo pi)
{
return a.Table.Where(t => (bool)(pi.GetGetMethod().Invoke(t, null))).AsQueryable<Table>();
}
To construct the PropertyInfo object, use something like:
PropertyInfo pi = typeof(Table).GetProperty("Owner");
I prefer the earlier method, but I did want to show that something like this is at least possible.
If you only want to specify the property you are checking you can do
public IEnumerable<Table> GetTables(Func<Table,bool> getValue)
{
return a.Table.Where(table => /*some common filter*/)
.Where(table => getValue(table))
}
var query = from u in uSrc join v in vSrc on u.ID equals v.RelatedUID
where v.Valid && u.Created < DateTime.UtcNow.AddDays(-365)
select u; // relatively complicated starting point.
var q1 = query.Where(u => u.Add); // must also have Add true
var q2 = query.Where(u => u.Test); // must also have Test true
var q3 = query.Where(u => u.ID < 50); // must also have ID < 50
And so on.
Edit:
Okay, so your starting query is:
List<Permission> clearence = student.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner)).ToList();
However, note that this creates a list, so any further work done on it will be a matter of Linq-to-objects. We'll come back to that in a minute, as it's sometimes good and sometimes not.
Now, if I understand you correctly, you need different sets for different cases, which you can do with your query as per:
var set0 = clearance.Where(u.Add = true || u.Owner == true);
var set1 = clearance.Where(u.Edit = true || u.Owner == true);
var set2 = clearance.Where(u.Delete= true || u.Owner == true);
var set3 = clearance.Where(u.View= true || u.Owner == true);
Now, this will work, but may not be the best approach. If we go back to the original query, we don't have to do ToList(), but can have:
IQueryable<Permission> clearence = student.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner));
Now, in the first case because we built a list we first got all values that matched the critera backed, and then stored it in memory, in clearance.
In the second case, clearance doesn't store any values at all, but instructions on how to get them.
The question is which is better to use. In the case where we are going to end up using the vast majority of the objects returned by the first query on its own, then there is a performance boost in using the list version, because they are loaded into memory only once, and then taken from memory without hitting the database again.
However, in most cases, it's better to do the second version for two reasons:
We hit the database in each case, but only retrieve the objects needed in that case.
We don't store anything in memory longer than necessary. Above a certain amount this is an important performance matter in itself.
The time to first item is faster this way.
We can further refine, for example if we do the following:
var trimmed = from set0 select new{u.Id, u.Permission.Name};
The we retrieve anonymous objects with Id and Name properties that are all we care about for a particular case, and not all of the relevant fields are retrieved from the database, or other source.
I've recently come to prefer a Dictionary over switch statements. You could store all your lambas in a Dictionary<PermissionNeeded, Func<User, bool>> that would look like this:
Dictionary<PermissionNeeded, Func<User, bool>> Permissions =
new Dictionary<PermissionNeeded, Func<User, bool>> {
{ PermissionNeeded.Add, u => u.Add }, // don't need to specify == true
{ PermissionNeeded.Edit, u => u.Edit },
...
etc
};
And you would call it like this:
var clearance = Permissions[PermissionNeeded.Add](user);
or maybe
var clearance = Permissions[PermissionNeeded.Add](user) && Permissions[PermissionNeeded.Edit](user);
or perhaps
var clearance = Permission[PermissionNeeded.Add](user) || Permissions[PermissionNeeded.View](user);
and so on. Even if you don't have a user object, I think this would still be valid and make the code pretty easy to read, and if you have to modify your functions, its all in the dictionary...

Linq, should I join those two queries together?

I have a Logins table which records when user is login, logout or loginFailed and its timestamp. Now I want to get the list of loginFailed after last login and the loginFailed happened within 24 hrs.
What I am doing now is get the last login timestamp first. then use second query to get the final list. do you think I should join those two queries together? Why not? Why yes? And how if yes?
var lastLoginTime = (from inRecord in db.Logins
where inRecord.Users.UserId == userId
&& inRecord.Action == "I"
orderby inRecord.Timestamp descending
select inRecord.Timestamp).Take(1);
if (lastLoginTime.Count() == 1)
{
DateTime lastInTime = (DateTime)lastLoginTime.First();
DateTime since = DateTime.Now.AddHours(-24);
String actionStr = "F";
var records = from record in db.Logins
where record.Users.UserId == userId
&& record.Timestamp >= since
&& record.Action == actionStr
&& record.Timestamp > lastInTime
orderby record.Timestamp
select record;
}
In the long run, I don't think it'd matter. No matter how you actually build the query in LINQ to SQL, the ultimate sequence of events on the DB server will be
get lastInTime
use lastInTime as part of records filter
Now... doing it as part of a single query will save on roundtrips of the actual date-time, so you can get some performance that way. But I would suggest that you only try to merge them if you absolutely need to because your performance profiling suggested that query was a bottleneck.
I don't think you should combine them because your current queries are quite readable. I think if they were combined it would be more difficult to understand the code.
I wouldn't merge, for reasons already stated by everyone else, but you can simplify the first query a bit: instead of
orderby inRecord.Timestamp descending
select inRecord.Timestamp).Take(1);
you can simply say:
select inRecord.Timestamp).Max();
It'll do the same thing, but it's a bit clearer than your way.
You can also use the IQueryable objects to compose more complex queries and still keep the code pretty easy to read. (I mixed the Extension syntax and query syntax just to show it can be done. You can just as easily swap this code around to separate it out as you would any other code in your solution.)
var usersRecords = db.Logins.Where(r => r.Users.UserId == userId);
var userLoginTimes = usersRecords.Where(r => r.Action == "I")
.Select(r => r.Timestamp);
var usersFunctions = usersRecords.Where(r => r.Action == "F");
var records = from record in usersFunctions
where userLoginTimes.Any()
let lastLoginTime = userLoginTimes.Max()
where record.Timestamp >= since
&& record.Timestamp > lastLoginTime
select record;

Select Single Value with ADO.Net Data Services and LINQ

Trying my hand at ADO.Net data services. All the examples shows how to retrieve lists but how would you go about retrieving a single value? e.g. Product X's Price.
Here is the LINQ query i use:
var qry = (from p in
svcContext.Products
where p.ProductName == "Chair"
&& p.Colour == 1
select c) as DataServiceQuery;
Product returnedProd;
qry.BeginExecute(
(pr) => returnedProd = qry.EndExecute(pr).First(), null);
Here i try to retrieve the product and load it into a local variable, but the local var stays null.
Pretty sure, i'm doing it completely wrong :)...any help would be greatly appreciated.
It's not suppose to be
var qry = (from p in svcContext.Products where p.ProductName == "Chair" && p.Colour == 1 select p) where did you declare the c ?
Sorry was supposed to be
var qry = (from p in
svcContext.Products where
p.ProductName == "Chair" && p.Colour
== 1 select p) as DataServiceQuery< Product >;
First() should throw an exception if the result set is empty - are you sure the query is even executing?
You are not the first to get hit by the asynchronous nature of all silverlight outgoing requests.
In the lambda expression
(pr) => returnedProd = qry.EndExecute(pr).First()
you capture the local variable returnedProd but usually the thread that will spin off AFTER BeginExecute has been called will be too late. It will probably executed after the execution goes out of scope of the current method and the variable will be lost.
The solution is to use effectively the "returnedProd" to populate the UI or whatever you need to do IN the lambda expression. Something like :
(pr) => {
returnedProd = qry.EndExecute(pr).First();
MessageBox.Show("Retrieved record" + returnedProd.Id);
}
Otherwise useful answer for the community, I wish I had one a few weeks ago :(

Categories