Wrong selection from database using Entity Framework - linq

I have a method that selects two fields from database where text in first field match some value
public static List<List<string>> SelectForSearch(string letter)
{
var data = (from p in model.City
where p.Name.StartsWith(letter)
select new List<string> { p.Name, p.CountryName }).ToList();
return data;
}
But it returns me a list like this:
[0][0]Australia
[0][1]Ballina
[1][0]Berry
[1][1]Australia
[2][0]Australia
[2][1]Bendigo
...
Country and City possition don't have a static index like this:
[0][0]Ballina
[0][1]Australia
[1][0]Berry
[1][1]Australia
[2][0]Bendigo
[2][1]Australia
...

Your issue is that in your select statement, instead of creating a type with Name and CountryName you are creating a List of strings. The List initialiser allows you to pass in the values when the list is constructed by placing them in { } and you are using this ability by accident, as you saw it creates a list of strings where the name is the first element and the country name is the second element. What you want to be doing is more like:
var data = (from p in model.City
where p.Name.StartsWith(letter)
select new { City = p.Name, CountryName = p.CountryName }).ToList();
return data;
This is using anonymous types which is not good as you want to declare a type for the return value. So you should really create a class for storage, for example:
public class CityCountryPair
{
public String City { get; set; }
public String CountryName { get; set; }
}
then your method becomes
public static List<CityCountryPair> SelectForSearch(string letter)
{
var data = (from p in model.City
where p.Name.StartsWith(letter)
select new CityCountryPair() { City = p.Name,
CountryName = p.CountryName
}).ToList();
return data;
}

Related

SELECT result map to entity in Dynamic Linq in Entity Framework Core

I have a Linq query which is selecting 2 columns(that can be any 2 from all columns) dynamically based on some condition.I need to map the query result in to below model irrespective of selected column names
public class FinalModel
{
public string Text { get; set; }
public string Id { get; set; }
}
Currently I am using reflection to map the result in to that model because i am getting some anonymous list of objects and it is working fine, But I want to remove that reflection and need to add the mapping in the select itself, my current implementation is like below
string column1 = "Name" //can be other columns also
string column2 = "Age"
var result = _context.table1
.Select("new ("+ column1 +","+ column2 +")")
.Distinct()
.Take(10) // having more records in table
.ToDynamicList()
.Select(x => new FinalModel()
{
Id = x.GetType().GetProperty(column1).GetValue(x).ToString(),
Text = x.GetType().GetProperty(column2).GetValue(x).ToString(),
});
The above code is working fine but I need to remove the below section
.Select(x => new FinalModel()
{
Id = x.GetType().GetProperty(column1).GetValue(x).ToString(),
Text = x.GetType().GetProperty(column2).GetValue(x).ToString(),
});
Is there any way to remove the refletion and add that model mapping directly inside Select("new (column1,column2)")
Is there any way to add orderBy with Column2 variable?
You can use generic versions of Select and ToDynamicList and OrderBy($"{column2}") for sorting:
var result = _context.table1
.Select<FinalModel>($"new ({column1} as Id, {column2} as Text)")
.Distinct()
.OrderBy("Text")
.Take(10)
.ToDynamicList<FinalModel>();
Or if you want to stick with dynamic:
var result = _context.table1
.Select($"new ({column1}, {column2})")
.Distinct()
.OrderBy($"{column2}")
.Take(10)
.ToDynamicList()
.Select(d => new FinalModel()
{
Id = d[column1].ToString(),
Text = d[column2].ToString(),
})
.ToList();
You need to use .Select<T> instead of just .Select() to make sure that the selected entity the correct type. So in your case you need .Select<FinalModel>.
Use the as cast operator to "rename" the properties from the source-entity to the destination entity (FinalModel)
If you want the result to be typed, also use .ToDynamicList<FinalModel>().
Full example code below:
using System.Linq.Dynamic.Core;
class Program
{
static void Main(string[] args)
{
var myQuery = new[] { new XModel { Age = "1", Name = "n" } }.AsQueryable();
string column1 = "Name";
string column2 = "Age";
var result = myQuery
.Select<FinalModel>("new (" + column1 + " as Id, " + column2 + " as Text)")
.Distinct()
.Take(10)
.ToDynamicList<FinalModel>();
Console.WriteLine(result[0].Id + " " + result[0].Text);
}
public class XModel
{
public string Name { get; set; }
public string Age { get; set; }
}
public class FinalModel
{
public string Text { get; set; }
public string Id { get; set; }
}
}

Linq results type?

I would like to replace "var" with the actual type definition. I believe it returns an IEnumerable<>, but I can't figure out what to put for T? I tried debugging with GetType(), but still don't get it...
var LinqResults = from row in dt.AsEnumerable()
orderby row.Field<string>("Category"), row.Field<int>("WorkOrderVersion")
group row by new { Category = row.Field<string>("Category"), WorkOrderVersion = row.Field<int>("WorkOrderVersion") } into grp
select new
{
Category = grp.Key.Category,
WorkOrderVersion = grp.Key.WorkOrderVersion,
};
You can't combine a use of an anonymous type with a specific type because anonymous types provide no name for you to put in for a T inside IEnumerable<T>. In fact, use of anonymous types is an important use case for adding var to the C# language in the first place.
You can define a named type for the result, lie this:
class VersionedWorkOrder {
public string Category { get; set; }
public int WorkOrderVersion { get; set; }
}
IEnumerable<VersionedWorkOrder> linqResults = from row in dt.AsEnumerable()
orderby row.Field<string>("Category"), row.Field<int>("WorkOrderVersion")
group row by new { Category = row.Field<string>("Category"), WorkOrderVersion = row.Field<int>("WorkOrderVersion") } into grp
select new VersionedWorkOrder {
Category = grp.Key.Category,
WorkOrderVersion = grp.Key.WorkOrderVersion
};

Combine Parent and Child Lists into a single nested Parent List

I have two lists, a parent list (parents) and a child list (children) with the child list having a parentId.
List<Parent> parents
List<Child> children
I am trying to combine the two lists into a single list of parents with each parent object having a list of children. I'm currently looping through the parent list and populating the Children list within each parent object based on the parentId but I was wondering if there was a faster way to do this using LINQ.
foreach (var parent in parents)
{
parent.Children = children.Where(c=>c.ParentId == parent.Id).ToList();
}
Any suggestions?
You can use a Join, combined with a GroupBy:
var parentChildrenQry =
from parent in parents
join child in children on parent.Id equals child.ParentId
group child by parent;
foreach(var grp in parentChildrenQry) {
grp.Key.Children = grp.ToList();
}
Or both in one statement with GroupJoin:
var parentChildrenQry =
parents.GroupJoin(children, parent.Id, child.ParentId, new { (parent, childGrp) => new { Parent = parent, Children = childGrp.ToList() } );
foreach(var grp in parentChildrenQry) {
grp.Parent.Children = grp.Children;
}
From a performance point of view there is nothing wrong with your foreach.
If your code is readable enough there is no point to make your code linq and fancy.
If your collections are very large, from performance perspective it might be most efficient if you firstly group your children by parent id and sort groups by parent id and get them appended to the sorted parents.
I know it is an old question but I'd like to share my experience
for me I have a lot of records in database so the performance is important I crate it in another way and get the result about 3 times faster. I get all data in one select then put results in my models.
I have restaurant database with menus and dishes tables.
At first these are the classes models that will handle the selected data and are different from database models
public class Menu
{
public Menu()
{
Dishes = new List<Dish>();
}
public long ID { get; set; }
public string Name { get; set; }
public string ImagePath { get; set; }
public List<Dish> Dishes { get; set; }
}
public class Dish
{
public long ID { get; set; }
public string Name { get; set; }
public string PicturePath { get; set; }
public double Price { get; set; }
}
This is the Linq query
var all = (from m in contexts.RestMenus
join d in contexts.ResDishes on m.Id equals d.MenuID
select new
{
Menu = new Menu()
{
ID = m.MenuID,
Name = m.Name,
ImagePath = m.ImageURL
},
Dish = new Dish()
{
ID = d.ItemID,
Name = d.Name,
PicturePath = d.PicturePath,
Price = d.DefaultPrice
}
}).ToList();
and the foreach loop to arrange the data
List<Menu> menus = new List<Menu>();
foreach (var r in all)
{
Menu m = menus.Find(x => x == r.Menu);
if (m == null)
{
menus.Add(r.Menu);
m = r.Menu;
}
m.Dishes.Add(r.Dish);
}

LINQ to return list of Object filtered on a property of a Child object in nested List<>

I'm looking for some help with a LINQ query to filter on a property/enum of a custom object which is in a nested List, and want to maintain the parent object in return list.
For example/clarity/sample code, I have a parent object, which has in it a List based on class and enum below:
public class Stage {
public String Name { get; set;}
public List<Evaluation> MyEvaluations { get; set;}
}
public class Evaluation {
public float Result { get; set; }
public enumResultType ResultType { get; set; }
}
public enum enumResultType {
A,B,C
}
One can simulate sample data along those lines with something like:
List<Stage> ParentList = new List<Stage>();
Stage Stage1 = new Stage() { Name = "Stage1",
MyEvaluations = new List<Evaluation>() {
new Evaluation() { ResultType = enumResultType.A, Result=5 },
new Evaluation() { ResultType = enumResultType.B, Result=10},
new Evaluation() { ResultType = enumResultType.B, Result=11},
new Evaluation() { ResultType = enumResultType.C, Result=5}
}};
Stage Stage2 = new Stage() { Name = "Stage2",
MyEvaluations = new List<Evaluation>() {
new Evaluation() { ResultType = enumResultType.A, Result=10},
new Evaluation() { ResultType = enumResultType.B, Result=20},
new Evaluation() { ResultType = enumResultType.C, Result=20}}};
ParentList.Add(Stage1);
ParentList.Add(Stage2);
What I want to be able to do, via LINQ, is to select from the Parentlist object, all the items with only a filtered list where the ResultType in the Evaluations List matches a proper condition...
I don't want to repeat the parent object multiple times (seen selectmany), but rather a filtered down list of the MyEvaluations where the ResultType matches, and if this list has items (it would) return it with the parent.
I've played with:
ParentList.Select(x => x.MyEvaluations.FindAll(y => y.ResultType==enumResultType.B)).ToList();
however this returns only the inner list... whereas
ParentList.Where(x => x.MyEvaluations.Any(y => y.ResultType==enumResultType.B)).ToList();
returns ANY.. however I am missing how to get the list of MyEvaluations to be filtered down..
In my Example/sample data, I would like to query ParentList for all situations where ResultType = enumResultType.B;
So I would expect to get back a list of the same type, but without "Evaluation" which are equal to ResultType.A or .C
Based on dummy data, I would expect to be getting something which would have:
returnList.Count() - 2 items (Stage1 / Stage2) and within that Stage1 --> foreach (item.Result : 10, 11 Stage2 --> foreach (item.Result : 20
Can this be done without going to projections in new anonymous types as I would like to keep the list nice and clean as used later on in DataBinding and I iterate over many ResultTypes?
Feel like I'm missing something fairly simple, but fairly new to LINQ and lambda expressions.
Did you try these approaches already? Or is this not what you're looking for ?
//creating a new list
var answer = (from p in ParentList
select new Stage(){
Name = p.Name,
MyEvaluations = p.MyEvaluations.Where(e => e.ResultType == enumResultType.B).ToList()
}).ToList();
//in place replacement
ParentList.ForEach(p => p.MyEvaluations = p.MyEvaluations.Where(e => e.ResultType == enumResultType.B).ToList());

Dynamic Column Name in LinQ

I am having a class Item.
class Item{
public int Id { get; set; }
public DateTime CreatedDate { get; set; }
public string Name { get; set; }
public string Description { get; set;}
}
I want to filter list of items based on dynamic column name.
Suppose I want list of Names then Column Name is "Name" and result will be list of names
If column name is Description, I need list of descriptions.
How to do this with LinQ?
Easy, just select the property you need from the list:
var items = new List<Item>();
//get names
var names = items.Select(x => x.Name);
//get descriptions
var descriptions = items.Select(x => x.Description);
Update:
You'll need a bit of reflection to do this:
var names = items.Select(x => x.GetType().GetProperty("Name").GetValue(x));
Throw this in a method for re-usability:
public IEnumerable<object> GetColumn(List<Item> items, string columnName)
{
var values = items.Select(x => x.GetType().GetProperty(columnName).GetValue(x));
return values;
}
Of course this doesn't validate wether the column exists in the object. So it will throw a NullReferenceException when it doesn't. It returns an IEnumerable<object>, so you'll have to call ToString() on each object afterwards to get the value or call the ToString() in the query right after GetValue(x):
public IEnumerable<string> GetColumn(List<Item> items, string columnName)
{
var values = items.Select(x => x.GetType().GetProperty(columnName).GetValue(x).ToString());
return values;
}
Usage:
var items = new List<Item>(); //fill it up
var result = GetColumn(items, "Name");

Resources