LINQ sorting on sub table converted to CSV - linq

I have an EF model (note joined partial classes togther for clarity)
public class Product
{
public System.Guid ProductID { get; set; }
public string Product{ get; set; }
public virtual ICollection<Module> Modules { get; set; }
[NotMapped]
public string ModulesCSV
{
get
{
string retList = "";
foreach (Module aModule in Modules)
{
if (retList.Length > 0)
retList += ", ";
retList += aModule.Module.Trim ();
}
return retList;
}
}
}
now I need to sort on the CSV as well as the other columns, I realise that link to sql has problems wth this. My normal sort cannot do this I was wondering if anyone knows a good way of doing it va LINQ and could please share it?
The current sort line is where 'sort' is the column name and 'sortdir' is "ASC" or "DESC" which works a treat for the other columns.
query = db.Products.AsExpandable().Where(predicate).OrderBy(sort + " " + sortdir);

Not pretty or as efficient but
if (sort != "CSV") // as non ddb column has to be sorted on list
query = db.Products.AsExpandable().Where(predicate).OrderBy(sort + " " + sortdir);
else
{
query = db.Products.AsExpandable().Where(predicate);
if (sortdir=="ASC")
{
query = db.Products.AsExpandable().Where(predicate).ToList<Product>().AsQueryable <Product> ();
query = query.OrderBy(r => r.GetType().GetProperty(sort).GetValue(r, null));
}
else
{
query = db.Products.AsExpandable().Where(predicate).ToList<Product>().AsQueryable <Product> ();
query = query.OrderByDescending(r => r.GetType().GetProperty(sort).GetValue(r, null));
}
}

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; }
}
}

How could I read one to many linked table using link with Entity Framework?

I am new to Entity Framework and Linq (Visual Studio 2017 - EF 5.0) . Currently, I could read tables without issue but wonder how could I read a linked table.
My current functions do it but sure there is a simple way than two step reading that I have developed.
public override List<CartItem> GetMyCartOrderItems(int UserID)
{
try
{
using (foodorderingdbEntities oMConnection = new foodorderingdbEntities())
{
var oCart = oMConnection.carts.SingleOrDefault(p => p.USER_ID == UserID);
if (oCartItems != null)
{
int CartID = oCart.CART_ID;
var oCartItems = oMConnection.cart_item.Where(p => p.CART_ITEM_CART_ID == CartID);
if (oCartItems != null)
{
List<CartItem> oRecList = new List<CartItem>();
foreach (cart_item oDBrec in oCartItems)
{
CartItem oRec = new CartItem();
oRec.CartID = oDBrec.CART_ITEM_ID;
oRec.CartItemID = oDBrec.CART_ITEM_CART_ID;
oRec.DateTime = oDBrec.CART_ITEM_ADDED_DATE_TIME;
oRec.SystemComments = oDBrec.CART_ITEM_SYSTEM_COMMENTS;
oRecList.Add(oRec);
}
return oRecList;
}
else { return null; }
}
else { return null; }
}
}
catch (Exception ex)
{
//IBLogger.Write(LOG_OPTION.ERROR, "File : MHCMySQLDataConection.cs, Method : GetPatientByID(1), Exception Occured :" + ex.Message + Environment.NewLine + "Trace :" + ex.StackTrace);
return null;
}
}
You could see that I get Cart ID from Carts table using UserID and then I use the CartID retrieve cart Items from Cart_Item table. Cart_Item_Cart_ID is a foreign key in cart_item table. (This is a one to many table)
This is what I am thinking but obviously does not work.
List<cart_item> oCartItems = oMConnection.carts.SingleOrDefault(c => c.USER_ID == UserID).cart_item.Where(p => p.CART_ITEM_CART_ID = c.CART_ID).ToList<cart_item>();
Any help ?
My entity relation
public partial class cart
{
public cart()
{
this.cart_item = new HashSet<cart_item>();
}
public int CART_ID { get; set; }
public int USER_ID { get; set; }
public decimal ORDER_TOTAL_COST { get; set; }
public virtual ICollection<cart_item> cart_item { get; set; }
public virtual user user { get; set; }
}
Because your query has multiple levels of one to many relationships, and you just want the cart_items, it's easier to go the other way like this:
var oCart = oMConnection.cart_item
.Where(c=>c.cart.user.USER_ID == UserID);
Going the way you did should have worked as well, but you needed to use SelectMany instead of select like this:
var oCartItems = oMConnection.carts
.Where(c=>c.USER_ID==UserID)
.SelectMany(c=>c.cart_item);

Linq to Sql Using a function to set a value

I wanted to get from a database a IEnumerable<T> and within the 'Select' method using a function to return a string value. But I always get back the
'method cannot be translated into a store expression'
error.
I already took a look all the post on Stack Overflow about the error 'LINQ to Entities does not recognize the method .... and this method cannot be translated into a store expression"
The only way that I found to get around this error is apply the function after the query has run.
void Main()
{
int eventId = 17;
IEnumerable<OccurrenceDropDownList> model = Occurrences.Select (s => new OccurrenceDropDownList
{
OccurrenceId = s.OccurrenceId,
Name = s.Name
})
.AsEnumerable()
.Select(m => new OccurrenceDropDownList
{
OccurrenceId = m.OccurrenceId,
Name = m.Name,
Selected = setSelected(m.OccurrenceId, eventId)
}).AsEnumerable();
foreach(var item in model)
{
Console.WriteLine(item.Name + " - id : " + item.OccurrenceId + " " + item.Selected);
}
}
public class OccurrenceDropDownList
{
public int OccurrenceId { get; set; }
public string Name { get; set; }
public string Selected { get; set; }
}
static string setSelected(int occurrence, int selectedid){
if(occurrence == selectedid){
return "selected";
}
return "";
}
Is there any way to apply the function as result of the first query?
It should be simplier:
int eventId = 17;
IEnumerable<OccurrenceDropDownList> model = Occurrences
.Select(s => new OccurrenceDropDownList
{
OccurrenceId = s.OccurrenceId,
Name = s.Name,
//magic ternary if
Selected = (eventId == s.OccurrenceId) ? "selected" : String.Empty
});
That's all. I used ternary if operator that should be translated to SQL.

How to convert LINQ query result to list and return generic List?

I used generic ORM list
example.
This is my table.
Person table
Guid
Name
LastName
and this is my struct class.
public struct PersonItem // database and class field names are the same
{
public Guid Guid{ get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
public struct PersonItems
{
public PersonItems()
{
Items = new List<PersonItem>();
}
public List<PersonItem> Items { get; set; }
}
I'm using such and no problem but I always have to write field's
public PersonItems GetPersons()
{
var query = (from p in _DbEntities.t_Crew
select p).ToList();
if (query != null)
{
foreach (var item in query)
{
_PersonItems.Items.Add(new PersonItem
{
Guid = item.Guid,
Name = item.Name,
LastName = item.LastName
});
}
}
return _PersonItems;
}
public PersonItems GetPersons()
{
PersonItems personItems = new PersonItems();
var query = from p in _DbEntities.t_Person
select p; >> this here query I need to convert linq query result to list
personItems = query.ToList();
return personItems ;
}
error
Cannot implicitly convert type System.Collections.Generic.List' to PersonData.PersonItems'.
Try this
public PersonItems GetPersons()
{
PersonItems personItems = new PersonItems();
var query = (from p in _DbEntities.t_Person
select new PersonItems
{
test = p.SomeName,
//Other Stuff
//...
}).ToList();
return query;
}
Comparing to the other version of your GetPersons() method, I think this line :
personItems = query.ToList();
should've been this way instead :
personItems.Items = query.ToList();
Update regarding the latest error. You can't assign list of t_Person to Item property which is of type list of PersonItem. Hence, your query need to be adjusted to return list of PersonItem :
var query = from p in _DbEntities.t_Person
select new PersonItem
{
Guid = p.Guid,
Name = p.Name,
LastName = p.LastName
};
or other option is to change definition of Item property to list of t_Person :
public List<t_Person> Items { get; set; }
Cannot implicitly convert type System.Collections.Generic.List' to PersonData.PersonItems'
Above error says that you are trying to convert generic list to PersonItems.
So at this line, query.ToList() code returns List<PersonItem> not the PersonItems
var query = from p in _DbEntities.t_Person
select p; >> this here query I need to convert linq query result to list
personItems = query.ToList();
return personItems ;
So thats the reason above line of code fails.
What about this?
Change .ctor of PersonItems:
public struct PersonItems
{
public PersonItems(List<PersonItem> items)
{
Items = items;
}
public List<PersonItem> Items { get; set; }
}
And then method GetPersons():
public PersonItems GetPersons()
{
return new PersonItems(_DbEntities.t_Person.ToList());
}

Sorting a List of Class with LINQ

I have a List<MyClass> and I want to sort it by DateTime CreateDate attribute of MyClass.
Is that possible with LINQ ?
Thanks
To sort the existing list:
list.Sort((x,y) => x.CreateDate.CompareTo(y.CreateDate));
It is also possible to write a Sort extension method, allowing:
list.Sort(x => x.CreateDate);
for example:
public static class ListExt {
public static void Sort<TSource, TValue>(
this List<TSource> list,
Func<TSource, TValue> selector) {
if (list == null) throw new ArgumentNullException("list");
if (selector == null) throw new ArgumentNullException("selector");
var comparer = Comparer<TValue>.Default;
list.Sort((x,y) => comparer.Compare(selector(x), selector(y)));
}
}
You can enumerate it in sorted order:
IEnumerable<MyClass> result = list.OrderBy(element => element.CreateDate);
You can also use ToList() to convert to a new list and reassign to the original variable:
list = list.OrderBy(element => element.CreateDate).ToList();
This isn't quite the same as sorting the original list because if anyone still has a reference to the old list they won't see the new ordering. If you actually want to sort the original list then you need to use the List<T>.Sort method.
Here is a sample:
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
public class Test
{
public void SortTest()
{
var myList = new List<Item> { new Item { Name = "Test", Id = 1, CreateDate = DateTime.Now.AddYears(-1) }, new Item { Name = "Other", Id = 1, CreateDate = DateTime.Now.AddYears(-2) } };
var result = myList.OrderBy(x => x.CreateDate);
}
}
public class Item
{
public string Name { get; set; }
public int Id { get; set; }
public DateTime CreateDate { get; set; }
}
}
Sure the other answers with .OrderBy() work, but wouldn't you rather make your source item inherit from IComparable and just call .Sort()?
class T {
public DateTime CreatedDate { get; set; }
}
to use:
List<T> ts = new List<T>();
ts.Add(new T { CreatedDate = DateTime.Now });
ts.Add(new T { CreatedDate = DateTime.Now });
ts.Sort((x,y) => DateTime.Compare(x.CreatedDate, y.CreatedDate));

Resources