SELECT SQLite.NET records where IDs match int array - c#

I am using SQLite.NET. I am trying to pass an integer array to a search query. I would like to return a list of records where the IDs (table attributes) match the integers in an array. The array is of size 10.
In MainPage.cs:
int[] arr = new int[10];
// for testing purposes
for (int i = 0; i <= 9; i++{
arr[i] = i;
}
var selected = App.Database.SearchList(arr);
In SQLiteDatabase.cs:
public List<Rooms> SearchList(int[] ID)
{
return database.Query<Rooms>("SELECT * FROM Rooms WHERE ID = ?;", ID);
}
This results in the following error when the query is executed:
System.NotSupportedException: Timeout exceeded getting exception details
How can I return a list of records where the IDs match? Thank you.

use the IN keyword
WHERE ID IN (1, 2, 3, 4, 5)

Apparently SQLite.NET does not support passing in an array as a parameter.
This throws and exception:
var IDs = new[] { 1, 2 };
return database.Query<Rooms>("SELECT * FROM Rooms WHERE ID IN (?);", IDs);
In this case the only solution is to join the paramters in the SQL string. This works for int[], but when using strings you should beware of SQL injection.
var IDs = new[] { 1, 2 };
return database.Query<Rooms>($"SELECT * FROM Rooms WHERE ID IN ({string.Join(",", IDs)});");

You need to have 1 '?' per argument so you can create your query string like this:
string query = $"SELECT * FROM Rooms WHERE ID IN ({string.Join(",", IDs.Select(x => "?"))});"
This makes the IN clause like (?,?,...,?)
Then when calling Query its necessary to cast the arguments to an object array or you'll get the exception as mentioned by #Neil B like this:
return database.Query<Rooms>(query,IDs.Cast<object>().ToArray());

Related

Linq with multiple foreach inserting items to table

I have list of ids like this below
List<int> ids = new List<int>();
and then i have list of lengths which is also integers like this below..
List<int> lengths = new List<int>();
now i need to insert into table using linq query with the data format like this below
ID length
1 1
1 2
1 3
2 1
2 2
2 3
for that i am doing like this
foreach (var item in ids)
{
foreach (var item in lengths)
{
}
}
With the above way i am not able insert the multiple id's in the table .. I am hoping there should be better way to do this..
Could any one please suggest any ideas on this one that would be very grateful to me..
Thanks in advance.
If you wanted to project these 2 lists to a flattened list with LINQ, you could use SelectMany
Projects each element of a sequence to an IEnumerable and flattens
the resulting sequences into one sequence.
// projecting to an anonymous type
var results = ids.SelectMany(id => lengths.Select(length => new {id, length }));
// or projecting to a value tuple
var results = ids.SelectMany(id => lengths.Select(length => (id, length)));
If you really want a single loop, you can loop over the final result length and compute the indexes into each List:
var idsCount = ids.Count;
var lengthsCount = lengths.Count;
var totalCount = idsCount * lengthsCount;
for (int j1 = 0; j1 < totalCount; ++j1) {
var id = ids[j1 / lengthsCount];
var length = lengths[j1 % lengthsCount];
new { id, length }.Dump();
// insert id,length
}

IEnumerable.Select with index

I have the following code:
var accidents = text.Skip(NumberOfAccidentsLine + 1).Take(numberOfAccidentsInFile).ToArray();
where accidents is an array of strings.
I want to make a Linq transformation from the string array to an array of Accident objects as follows:
return accidents.Select(t => new Accident() {Id = i, Name = t.Replace("\"", string.Empty)}).ToArray();
How do I retrieve the index i from the accidents array using Linq or do I have to go old school?
I'm not sure what kind of index you're looking for, but if it's just set of consecutive numbers then you're lucky. There is Select overload that does exactly that:
return accidents.Select((t, i) => new Accident() {Id = i, Name = t.Replace("\"", string.Empty)}).ToArray();
It expects a delegate that takes two parameters - the item and its index.
Use Enumerable.Range to generate the ID values and then use the current value to index into your String Array:
Enumerable.Range(0, accidents.Length).Select(f => new Accident() { Id = f, Name = accidents[f] })
May be this LINQ query will help you to find The formated name with Index:
var accidents=(from acc in accidents
select new {
id=accidents.IndexOf(acc),
Name = acc.Replace("\"", string.Empty)
}).ToArray()
or you can also use .ToList() for the case if you want result to be in IEnumerable format.

Get min value in row during LINQ query

I know that I can use .Min() to get minimum value from column, but how to get minimum value in a row?
I have following LINQ query (for testing purposes):
from p in Pravidloes
where p.DulezitostId == 3
where p.ZpozdeniId == 1 || p.ZpozdeniId == 2
where p.SpolehlivostId == 2 || p.SpolehlivostId == 3
group p by p.VysledekId into g
select new {
result = g.Key,
value = g
}
Which results into this:
I would however like to get only the MIN value of following three columns:
DulezitostId, ZpozdeniId, SpolehlivostId as a value in:
select new {
result = g.Key,
value = g // <-- here
}
The final result then should look like:
result: 2, value: 1
result: 3, value: 2
I have been looking for similar questions here and googled for few examples with grouping and aggregating queries, but found nothing that would move me forward with this problem.
Btw: Solution isn't limited to linq, if you know better way how to do it.
You could create an array of the values and do Min on those.
select new {
result = g.Key,
value = g.SelectMany(x => new int[] { x.DulezitostId, x.ZpozdeniId, x.SpolehlivostId }).Min()
}
This will return the min for those 3 values in each grouping for ALL rows of that grouping.
Which would result in something like this...
result: 3, value: 1
The below will select the min for each row in the grouping...
select new {
result = g.Key,
value = g.Select(x => new int[] { x.DulezitostId, x.ZpozdeniId, x.SpolehlivostId }.Min())
}
Which would result in something like this...
result: 3, value: 1, 2
The best solution if you're using straight LINQ is Chad's answer. However, if you're using Linq To SQL it won't work because you can't construct an array like that.
Unfortunately, I believe the only way to do this in Linq To Sql is to use Math.Min repeatedly:
select new {
result = g.Key,
value = Math.Min(Math.Min(DulezitostId, ZpozdeniId), SpolehlivostId)
}
This will generate some ugly CASE WHEN ... statements, but it works.
The main advantage of doing it this way is that you're only returning the data you need from SQL (instead of returning all 3 columns and doing the Min in the application).

Working on lambda expression

I am squaring each integer in a List. Here is the code.
class SomeIntgs
{
List<int> newList = new List<int>();
public List<int> get()
{
IEnumerable<int> intrs = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
newList.AddRange(intrs);
return newList;
}
}
I am getting error in Main()
SomeIntgs stg = new SomeIntgs();
var qry = from n in stg.get() where (P => P*P) select n;
Error : "Can not convert lambda expression to type bool ".
Help Please.
Also help me, how can i handle lambda in general context
You don't need the where, try this:
SomeIntgs stg = new SomeIntgs();
var qry = from n in stg.get() select n*n;
or
var qry = stg.get().Select(P => P*P);
Enumerable.Where is used to filter elements from a sequence - what you really want to do is project a new sequence of elements like I have shown above.
The lambda that the where clause takes specifies how you match an item from your IQueryable. Any member of the IQueryable that satisfies the expression you supply will be returned. (This is why your compiler is complaining about bools).
As others have mentioned, you can drop the where clause to square each item in the list.
var ints = new int []{1,2,3,4,5,6,7,8};
var squares = ints.Select(x => x*x);
var evenSquares = ints.Where(x => (x % 2) == 0).Select(x => x*x); // only square
//the even numbers in the list
SomeIntgs stg = new SomeIntgs();
var qry = from n in stg.get() select n*n;

LINQ to SQL: Advanced queries against lists, arrays and lists of objects

Single and multiple lists
Consider the following lists:
List<Int32> appleIdentities = new List<int>(new[] { 1, 2, 3 });
List<Int32> chocolateIdentities = new List<int>(new[] { 2, 3, 4 });
List<Int32> icecreamIdentities = new List<int>(new[] { 11, 14, 15, 16 });
Using LINQ to SQL; is it possible to wite a statement which translates into:
SELECT
DesertsID,
DesertsName
FROM
Deserts
WHERE
Deserts.AppleIdentity IN (1, 2, 3) AND
Deserts.ChocolateIdentity IN (2, 3, 4) AND
Deserts.IcecreamIdentity IN (11, 14, 15m 16)
If yes; how would the code look if I wanted to query my database of deserts against just the appleIdentities list?
Arrays
Consider the following arrays:
Int32[] appleIdentities = new[] {1, 2, 3, 4};
String[] chocolateNames = new[] {"Light", "Dark"};
Using LINQ to SQL; is it possible to wite a statement which translates into:
SELECT
DesertsID,
DesertsName
FROM
Deserts
WHERE
Deserts.AppleIdentity IN (1, 2, 3) AND
Deserts.ChocolateName IN ('Light', 'Dark')
If yes; how would the code look if I wanted to query my database of deserts against just the appleIdentities array?
List of objects
Consider the following:
public class Identities
{
public Int32 appleIdentity { get; set; }
public String chokolateName { get; set; }
}
List<Identities> identities = new List<Identities>(new[] {
new Identities { appleIdentity = 1, chokolateName = "Light" },
new Identities { appleIdentity = 2, chokolateName = "Dark" },
});
Using LINQ to SQL; is it possible to wite a statement which translates into:
SELECT
DesertsID,
DesertsName
FROM
Deserts
WHERE
Deserts.AppleIdentity IN (1, 2) AND
Deserts.ChocolateName IN ('Light', 'Dark')
If yes; how would the code look if I wanted to query my database of deserts against just the appleIdentity-property on my list of Identities objects?
This is branch off of LINQ to SQL query against a list of entities
how would the code look if I wanted to
query my database of deserts against
just the appleIdentities list?
You can compose a linq query in multiple statements, like so, and select at runtime which filters your want to use in your where clause.
var query = db.Desserts;
if (filterbyAppleIdentity)
query = query.Where( q => appleIdentities.Contains(q.DesertsID));
if (filterbyChocolateIdentities)
query = query.Where( q => chocolateIdentities.Contains(q.DesertsID));
if (filterbicecreamIdentities)
query = query.Where( q => icecreamIdentities.Contains(q.DesertsID));
var deserts = query.ToList();
you can also write an extension method to do this without if statements: (Edit fixed typo, return type should be IQueriable
public static class LinqExtensions {
public IQueriable<T> CondWhere<T>(this IQueriable<T> query, bool condition, Expression<Func<T,bool>> predicate) {
if (condition)
return query.Where(predicate);
else
return query;
}
}
and write your linq query like this:
var deserts = db.Desserts;
.CondWhere(filterbyAppleIdentity, q => appleIdentities.Contains(q.DesertsID));
.CondWhere(filterbyChocolateIdentities, q => chocolateIdentities.Contains(q.DesertsID));
.CondWhere(filterbicecreamIdentities, q => icecreamIdentities.Contains(q.DesertsID)).ToList();
Another way to do it is to union the id lists:
var deserts = db.Deserts
.Where( d => appleIdentities.Union(chocolateIdentities).Union(icecreamIdentities).Contains(d.DesertsID);
For a list of objects you can use .Select extension method to project your list into a int or string IEnumerable and you can use contains in the query in the same way:
var deserts = db.Deserts
.Where(d =>
identities.Select(i => i.appleIdentity).Contains(d => d.DesertID) &&
identities.Select(i => i.chokolateName).Contains(d => d.DesertsName)
)
Sure - just use Contains - using Northwind as an example:
var qry = from cust in ctx.Customers
where custIds.Contains(cust.CustomerID)
&& regions.Contains(cust.Region)
select cust; // or your custom projection
Well, you can try:
var query = from dessert in db.Desserts
where appleIdentities.Contains(dessert.AppleIdentity)
&& chocolateIdentities.Contains(dessert.ChocolateIdentity)
&& iceCreamIdentities.Contains(dessert.IceCreamIdentity)
select new { dessert.Id, dessert.Name };
I believe that's okay, although it'll fail when the lists get big enough IIRC. That should be okay for lists and arrays.
I'm not sure about your third query though - I think you'd need a list for each of the separate Contains calls.
As others have said, LinqToSql will translate Contains to IN.
There's some caveats:
this translation works for List<T>.Contains(), but doesn't work for IList<T>.Contains(). Does it work for arrays? I don't know.
This translation will happily translate as many elements as you like - each element becomes a sql parameter. SQL Server 2008 has an approx 2000 parameter limit and will throw sql exceptions at you if you try this with a collection that is too big.
This translation, when applied to a collection of strings, will produce nvarchar parameters. This could be a serious problem if the target column is varchar and you want to use the index on this column. Sql Server will convert the index, instead of the parameters... which involves reading and converting every string in the whole index.
Here's some code for your List of Objects question:
List<int> someIDs = identities
.Select(x => x.appleIdentity).ToList();
List<string> someStrings = identities
.Select(x => x.chokolateName).ToList();
var query = db.Desserts.Where(d =>
someIDs.Contains(d.AppleIdentity) &&
someStrings.Contains(d.ChocolateName)
)

Categories