I am doing this in LINQ TO SQL:
var query = Database.ExtendedUsers.Select(x => x).Where(x => x.Acolumn >= 4);
which generates the correct SQL syntax (with where clause).
If I add a 2nd where, it is ignored:
var query = Database.ExtendedUsers.Select(x => x).Where(x => x.Acolumn >= 4);
query.Where(x => x.AnotherColumn.Equals(2));
The second where clause isn't added to the SQL query.
What am I doing wrong?
Basically, I want to dynamically add where's
query.Where(...);
query.Where(...);
query.Where(...);
query.ToList(); /: result
The problem is that Where returns new IQueryable implementation (with added proper nodes in Expression Tree that is used to generate SQL). So basically, you just need to assign result back to the query variable:
query = query.Where(x => x.AnotherColumn.Equals(2));
Editor: please do not change my post and add code I didn't have posted (add comment instead). The OP wants to use where dynamically (f.e. based on conditions). Sample:
var query = Context.MyTable.Where(tbl => tbl.Col > 4);
if (someConditionThatCannotBeEvalutedInLinqToSql)
{
query = query.Where(2)tabl => table.Col2 == 5);
}
So, Where(x => x.Acolumn >= 4 && x.AnotherColumn.Equals(2)) is not always solution and I don't believe that is what the OP needs.
Related
I want to search using soundex() with each words of a sentence.
My C# code is:
all_data = db.SearchEntities.Where(
s => (s.EventTitlePrimaryLang
.Split(' ')
.ToArray()
.Any(d => SqlFunctions.SoundCode(d.ToString()) ==
SqlFunctions.SoundCode(srQuery.ToString())
))
)
//.AsEnumerable()
//.AsQueryable()
.ToList();
Getting this error
LINQ to Entities does not recognize the method 'System.String[]
ToArrayString'
method, and this method cannot be translated into a store expression.
Your issue is that you are attempting to filter on the split results of a property in your query. Everything in the .Where() clause off the DbSet called SearchEntities will need to be evaluated as SQL.
The error message is telling you that EF can't convert x.MyProperty.Split() into SQL.
The only alternative, which might not be desirable in this case is to have a more general filter, then perform the complex filtering in you materialised results.
db.SearchEntities.Where(s => Something general to narrow down your results)
.AsEnumerable() // materialise your results
.Where(s => s.EventTitlePrimaryLang
.Split(' ')
.Any(d => something specific with your d and sQuery))
.ToArray();
all_data = db.SearchEntities.Where(x => !string.IsNullOrWhiteSpace(x.EventTitlePrimaryLang))
.ToList();
var filteredData = all_data.Where(s => (s.EventTitlePrimaryLang.Split(' ')
.Any(d => SqlFunctions.SoundCode(d)) == SqlFunctions.SoundCode(srQuery)))
.ToList();
OR
all_data = db.SearchEntities.Where(x => !string.IsNullOrWhiteSpace(x.EventTitlePrimaryLang))
.AsEnumerable()
.Where(s => (s.EventTitlePrimaryLang.Split(' ')
.Any(d => SqlFunctions.SoundCode(d)) == SqlFunctions.SoundCode(srQuery)))
.ToList();
As Pointed out by reckface in another answer.
OR
As another alternative to the above which may or may not work, you could opt to build the query using for loops.
var results = db.SearchEntities.Where(x => !string.IsNullOrWhiteSpace(x.EventTitlePrimaryLang))
.AsQueryable();
foreach(var r in results) {
var langSplit = s.EventTitlePrimaryLang.Split(' ');
foreach(var val in langSplit) {
results = from a in results
where SqlFunctions.SoundCode(val) == SqlFunctions.SoundCode(srQuery)
select a;
}
}
return results.ToList();
The above would then filter your results bit by bit.
EDIT:
Removed The redundant .ToString() calls
EDIT 2:
Edited the code example to better help fix the problem and Identify what is wrong.
The problem is that Entity Framework cannot convert .Split(' ') into valid SQL Code. As a work around, you will need to retrieve the data first, then filter that data using LINQ
EDIT 3:
Added possibly another way to solve the issue by using .AsQueryable() to filter down the results. Thus you don't need to query the database for a large dataset and filter the results, you could get the filtered results from the db directly, assuming it dosen't build the split into the database query. I have not tested it.
SELECT
[TimeStampDate]
,[User]
,count(*) as [Usage]
FROM [EFDP_Dev].[Admin].[AuditLog]
WHERE [target] = '995fc819-954a-49af-b056-387e11a8875d'
GROUP BY [Target], [User] ,[TimeStampDate]
ORDER BY [Target]
My database table has the columns User, TimeStampDate, and Target (which is a GUID).
I want to retrieve all items for each date for each user and display count of entries.
The above SQL query works. How can I convert it into LINQ to SQL? Am using EF 6.1 and my entity class in C# has all the above columns.
Create Filter basically returns an IQueryable of the entire AuditLogSet :
using (var filter = auditLogRepository.CreateFilter())
{
var query = filter.All
.Where(it => it.Target == '995fc819-954a-49af-b056-387e11a8875d')
.GroupBy(i => i.Target, i => i.User, i => i.TimeStamp);
audits = query.ToList();
}
Am not being allowed to group by on 3 columns in LINQ and I am also not sure how to select like the above SQL query with count. Fairly new to LINQ.
You need to specify the group by columns in an anonymous type like this:-
var query = filter.All
.Where(it => it.Target == '995fc819-954a-49af-b056-387e11a8875d')
.GroupBy(x => new { x.User, x.TimeStampDate })
.Select(x => new
{
TimeStampDate= x.Key.TimeStampDate,
User = x.Key.User,
Usage = x.Count()
}).ToList();
Many people find query syntax simpler and easier to read (this might not be the case, I don't know), here's the query syntax version anyway.
var res=(from it in filter.All
where it.Target=="995fc819-954a-49af-b056-387e11a8875d"
group it by new {it.Target, it.User, it.TimeStampDate} into g
orderby g.Key.Target
select new
{
TimeStampDate= g.Key.TimeStampDate,
User=g.Key.User,
Usage=g.Count()
});
EDIT: By the way you don't need to group by Target neither OrderBy, since is already filtered, I'm leaving the exact translation of the query though.
To use GroupBy you need to create an anonymous object like this:
filter.All
.Where(it => it.Target == '995fc819-954a-49af-b056-387e11a8875d')
.GroupBy(i => new { i.Target, i.User, i.TimeStamp });
It is unnecessary to group by target in your original SQL.
filter.All.Where( d => d.Target == "995fc819-954a-49af-b056-387e11a8875d")
.GroupBy(d => new {d.User ,d.TimeStampDate} )
.Select(d => new {
User = d.Key.User,
TimeStampDate = d.Key.TimeStampDate,
Usage = d.Count()
} );
I'm trying to find all customer codes where the customer has a status of "A" and whose code does not contain any letter using LINQ query.
var activeCustomers = Customers.Where(x => x.Status == "A" && x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code);
When I run this query in LinqPad I get the following error:
You'll need to do this as a two part query. First, you could get all the users who's status is "A":
var activeCustomers = Customers.Where(x => x.Status == "A").ToList();
After you've got those in-memory, you can create an additional filter for char.IsDigit:
var codes = activeCustomers.Where(x => x.Code.Any(n => !char.IsLetter(n)))
.Select(x => x.Code)
.ToArray();
As commenters have stated, IsLetter() cannot be translated to SQL. However, you could do the following, which will first retrieve all items with Status "A" from the database, then will apply your criteria after retrieval:
var activeCustomers = Customers.Where(x => x.Status == "A").AsEnumerable().Where(x => x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code);
You'll have to determine if it's acceptable (from a performance perspective) to retrieve all customers with "A" and then process.
The AsEnumerable() transitions your LINQ query to working not with IQueryable (which works with SQL) but with IEnumerable, which is used for plain LINQ to objects.
Since it is LINQ 2 SQL, there is no natural way to translate char.IsLetter to something SQL can understand. You can hydrate a query that retrieves your potential candidates and then apply an addition in-memory filter. This also solves the issue where LINQ 2 SQL has a preference for a string and you are dealing with chars
var activeCustomers = Customers.Where(x => x.Status == "A").ToList();
var filteredCustomers = activeCustomers.Where(x =>
x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code).ToList();
There are two performance hits here. First, you're retrieving all potential records, which isn't too desirable. Second, in your above code you were only interested in an enumerable collection of codes, which means our query is including far more data than we originally wanted.
You could tighten up the query by only returning back to columns necessary to apply your filtering:
var activeCustomers = Customers.Where(x => x.Status == "A")
Select(x => new Customer{ Status = x.Status, Code = x.Code }).ToList();
You still return more sets than you need, but your query includes fewer columns.
I'm trying to select one field last record in filtered database (this is different than last inserted record). I tried with following code in controller but instead of field value, i'm getting "true" or "false", depending on if there's results after filtering or not.
List<Pozicije> poz = new List<Pozicije>();
poz = db.Pozicijes.Where(p => p.grupa == grupa)
.OrderBy(p => p.sifra_pozicije).ToList();
string pos = poz.Select(p => p.sifra_pozicije.Contains(s)).LastOrDefault().ToString();
can someone point me how to get value i need instead?
Try this instead. I've combined both parts of your query into one.
var pos =
Convert.ToString(db.Pozicijes.Where(p => p.grupa == grupa
&& p.sifra_pozicije.Contains(s))
.OrderByDescending(p => p.sifra_pozicije)
.Select(p => p.sifra_pozicije)
.FirstOrDefault());
If it doesn't work, you may need to tell us what types s and sifra_pozicije are.
LastOrDefault is not supported with LINQ to Entities/LINQ TO SQL. You need to do OrderByDescending and then get First record. Like:
string pos = db.Pozicijes.Where(p => p.grupa == grupa && p.sifra_pozicije.Contains(s)))
.OrderByDescending(p=> p.sifra_pozicije)
.Select(r=> r.sifra_pozicije)
.First();
I have a List and i want to write a query about List's ids Contains specific table id.
i Write this and running true but i want to write all in same query..
List<int> tempList=yetkiUygulamaList.Select(y => y.Id).ToList();
query = query.Where(x => tempList.Contains(x.Uygulama.Id));
Wrong Query
query = query.Where(x => yetkiUygulamaList.Select(y =>y.Id).ToList().Contains(x.Uygulama.Id));
this must works
query = query.Where(x => yetkiUygulamaList.Any(y=>y.Id == x.Uygulama.Id));
you can perform a join, it would be more simple and suitable in your case.
If I understand, query is a "collection" of a class (let's call it AObj) containing a property Uygulama and the class Uygulama contains a property Id and yetkiUygulamaList is a "collection" of Uygulama
//will return a IEnumerable<AObj>
IEnumerable<AObj> query = query.Join(yetkiUygulamaList, a => a.Uygulama.Id, u => u.Id, (a,u)=>a);
ToList() materilizes by executing the query, and after that there is no way for NHibernate to understand that the first query should be included as a subquery.
Just remove the useless ToList():
IQueryable<int> tempList = yetkiUygulamaList.Select(y => y.Id); // removed here
query = query.Where(x => tempList.Contains(x.Uygulama.Id));
The above code will generate a single SQL query. If you want to stick it all in one C# code line, just get rid of the intermediary variable:
query = query.Where(x => yetkiUygulamaList.Select(y => y.Id).Contains(x.Uygulama.Id));