Sequence contains several elements Dapper - c#

I'm using Dapper for retrieve a result of my request SELECT.
List<dynamic> results = connection.Query("SELECT id_fonction from liste_personnels_fonctions where id_personnel = #id_personnel", new { id_personnel }).ToList();
But sometimes I have 2 results. When I use .SingleOrDefault() I have an exception : "Sequence contains several elements" when I have more than one row returned. When I use FirstOrDefault I have only first row and I need both of them...
So what can I do? I try with List<> and var[] to retrieve the results but it doesn't work.
Any ideas?
Thanks.

If you want just a list of Int then ask Dapper for that
List<int> results = connection.Query<int>("SELECT id_fonction from liste_personnels_fonctions where id_personnel = #id_personnel", new { id_personnel }).ToList();

Related

Using LINQ .Select and .Any in single line

I am looking to optimize some code to less lines and without the need for "for loops" using LINQ if possible. I saw a similar post asking for Select and Where in a single line but it wasn't exactly the same.
Suppose I have:
A list of elements in "fields" which has properties "Id" and "Name" which can be retrieved calling respectively .Id and .Name
Ex.
fields[0] = Element
fields[0].Id = 12345
fields[0].Name = Name01
I want to create a new list "filteredIds" containing the Id properties of selected fields.
This is the for loop version:
List<Id> filteredIds = new List<Id>();
fields = {Element1, Element2, ...}; //List of Elements
List<string> selectedNames = new List<string>() {"Name01", "Name05", "Name10"};
foreach (Element e in fields):
if (selectedNames.Contains(e.Name())
{
filteredIds.Add(e.Id);
}
Can this be done in a single line like this in LINQ?
filteredIds = fields.Select(i => i.Id).Any(o => selectedNames.Contains(o.Name)).ToList();
Any() returns true/false values. You need to call Where() to actually filter results.
filteredIds = fields.Where(o => selectedNames.Contains(o.Name)).Select(i => i.Id).ToList();
Almost correct. You should use Where to filter the list, not Any.
Any returns a boolean which is true if at least one element in the list satisfies the predicate, while Where returns all the elements that satisfy the predicate.
You also need to apply the Where filter before the Select, as the name property is removed by the select.

How to filter In memory Data object with LINQ and "In" statement

I'm trying to fill my DataGrid
dgGoals.ItemsSource = GetGoals(new int[] { 1, 2, 3 });
This is the In Memory object that has data loaded from a different process
static ObservableCollection<Goal> goals = new ObservableCollection<Goal>();
I tried using this example Linq version of SQL "IN" statement but both the lambda and LINQ statements are returning null when it should be 100 records.
public static ObservableCollection<Goal> GetGoals(int[] selectedGoalKey)
{
//goals has 170 records at this point
//selectedGoalKey has 3 items (1,2,3)
//goals has 100 records with Goal_Key of 1,2 or 3
//Returns null
return goals.Where(f => selectedGoalKey.Contains(f.Goal_Key)) as ObservableCollection<Goal>;
//Returns null
return (from g in _Goals
where selectedGoalKey.Contains(g.Goal_Key)
select g) as ObservableCollection<Goal>;
}
EDIT Fixed and now works
public static IEnumerable<Goal> GetGoals(int[] selectedGoalKey)
{
//goals has 170 records at this point
//selectedGoalKey has 3 items (1,2,3)
//goals has 100 records with Goal_Key of 1,2 or 3
//Now returns 100 records
return goals.Where(f => selectedGoalKey.Contains(f.Goal_Key));
//Now returns 100 records
return (from g in _Goals
where selectedGoalKey.Contains(g.Goal_Key)
select g);
}
The problem is that the result is not an ObservableCollection<Goal> but an IEnumerable<Goal>. That is why you are receiving null.
You can do:
return new ObservableCollecion<Goal>
(goals.Where(f => selectedGoalKey.Contains(f.Goal_Key)));
Using the "x" as "some type" casts the object to that type, and in the case it isn't able to returns null. What you want to do is to create a new ObservableCollecion and pass it the result of the linq query.
Out of MSDN:
The as operator is like a cast operation. However, if the conversion isn't possible, as returns null instead of raising an exception. Consider the following example:
Jmyster is not a good idea to work with ObservableCollection from the begining
Even with it inherits from Collection, it has much more boiler plates than you need while working on simple filters.(stuff like Notify events and more )
I´d strongly recommend you to make all your filltering using simple List, and only in the end of your algorithm put them all in a ObservableCollection class.
This simple behavior will prevent you from dealling with out-of-contexto problems.
Hope this help.

Linq to SQL select multiple columns

I just want to select 2 columns from a MSSQL DB using LINQ.
The SQL should be
select table.col1,table.col2 from table
I tried
IList<string> myResults =
(
from data in dbconn.table
where table.col5 == null
select new {
col1=data.Id.ToString(),
col2=data.col2
}
).Take(20).ToList();
but this didn't work.
It says
cannot convert type list <AnonymousType#1> to Ilist<string>
You are basically trying to fill a list of strings with the entries of a list of anonymous types, that won't work.
Have you tried something like this?:
var list = from data in dbconn.table
where table.col5 == null
select new {
col1=data.Id.ToString(),
col2=data.col2
}
Then you can easily use the entries in a loop for example
foreach(var element in list) {
//...
}
Or like a list
list.Take(20).ToList();
First of all, a list of strings (List<string>) can only have one single string in an element not two (what you are trying to do here) changing the type to var would fix your exception but not sure if that is the solution you want.
var myResults =
(
from data in dbconn.table
where table.col5 == null
select new {
col1=data.Id.ToString(),
col2=data.col2
}
).Take(20).ToList();
You can select multiple fields using linq Select as shown above in various examples this will return as an Anonymous Type. If you want to avoid this anonymous type here is the simple trick.
var items = myResults.Select(f => new [] { f.Col1, f.Col2 }).SelectMany(item => item).Distinct();
I think this solves the problem

How do I fill the "var" from a LINQ query into the same datatable?

I am fairly new to LINQ and am trying to apply this query on a datatable called "EmpInfo" to sort it.
var sortedRows = (from myRow in EmpInfoDS.Tables["EmpInfo"].AsEnumerable()
orderby myRow["EmpID"] ascending
select myRow).ToArray();
This works. The next thing I am trying to do is to copy the results into the SAME datatable.
EmpInfoDS.Tables["EmpInfo"].Clear();
EmpInfoDS.Tables["EmpInfo"] = sortedRows.CopyToDataTable();
The second line throws the following error:
"Property or indexer 'System.Data.DataTableCollection.this[string]'
cannot be assigned to -- it is read only"
Please some one tell me how to deal with this. And if there is another way please tell me.
The error says that you can't assign the table using indexers because Tables is a readonly property. So to solve the problem:
EmpInfoDS.Tables.Remove("EmpInfo");
DataTable dt = sortedRows.CopyToDataTable();
dt.TableName = "EmpInfo";
EmpInfoDS.Tables.Add(dt);
I think this is how it can be done: (you might prefer a different LoadOption)
EmpInfoDS.Tables["EmpInfo"].Clear();
sortedRows.CopyToDataTable(EmpInfoDS.Tables["EmpInfo"], LoadOption.OverwriteChanges);
This should also work:
EmpInfoDS.Tables["EmpInfo"].Clear();
foreach (var row in sortedRows)
EmpInfoDS.Tables["EmpInfo"].Rows.Add(row);
With LINQ, you have to watch out for deferred execution. Basically, queries are not executed until the data from the query is consumed. If you want a query to execute immediately, use the ToList() method.
var sortedRows = EmpInfoDS.EmpInfo.OrderBy(e => e.EmpID).ToList();
Next, the code is straight forward:
var employees = EmpInfoDS.EmpInfo;
employees.Clear();
foreach (var sortedRow in sortedRows)
employees.Add(sortedRow);
EmpInfoDS.SaveChanges();

Getting one list from another list using LINQ

I've seen the technique of taken a list of ObjectA and converting into a list of ObjectB where the two classes share some similar properties but is there an easier way to do that when you're just going from a list of ObjectA to another list of ObjectA?
Basically I want to do ...
var excv = from AuditedUser in data
where AuditedUser.IsMarkedForRemoval == false
select AuditedUser;
... but instead of a var I want the results to form a new List < AuditedUser > .
Is there something super easy I'm just missing?
var excv = (from AuditedUser in data
where AuditedUser.IsMarkedForRemoval == false
select AuditedUser).ToList();
I wrapped your LINQ statement with parens and added the ToList call at the end. Is this what you're looking for?
You could also do the following which is shorter to type and read I think:
List<AuditUser> excv = data.Where(a=>!a.IsMarkedForRemoval).ToList();

Categories

Resources