Why can't I use a dictionary with Entity Framework - c#

Dictionary<int, string> D = new Dictionary<int, string>();
D.Add(0, "Insert");
D.Add(1, "Update");
D.Add(2, "Delete");
using (SerasMacEntity SME = new SerasMacEntity())
{
var SQL = (from p in SME.tbl_admin_islem
let testx = D.Where(x => x.Key == p.islem).Select(x => x.Value).FirstOrDefault()
orderby p.tarih descending
select new
{
p.id,
p.islem,
p.tarih
});
Store1.DataSource = SQL;
Store1.DataBind();
}
Its giving this error;
'System.Collections.Generic.KeyValuePair`2' and Only primitive types
('such as Int32, String, and Guid')
I use this method in Linq but I can't use Entity.
public class table
{
public int ID { get; set; }
public string Adi { get; set; }
public int IslemID { get; set; }
public table() { }
public table(int _ID, string _Adi, int _IslemID)
{
_ID = ID;
_Adi = Adi;
_IslemID = IslemID;
}
}
public List<table> table_list = new List<table>(new table[]
{
new table{ID=1,Adi="A1",IslemID=0},
new table{ID=2,Adi="A2",IslemID=1},
new table{ID=3,Adi="A3",IslemID=2},
new table{ID=4,Adi="A4",IslemID=1},
new table{ID=5,Adi="A5",IslemID=0},
new table{ID=6,Adi="A6",IslemID=2},
new table{ID=7,Adi="A7",IslemID=0},
new table{ID=8,Adi="A8",IslemID=1},
new table{ID=9,Adi="A9",IslemID=3}
});
public Dictionary<int, string> option_dictionary = new Dictionary<int,string>()
{
{0, "OK"},
{1, "NO"},
{2, "YA"},
{3, "OH"}
};
public void TestL()
{
string b = option_dictionary.Where(x => x.Key == 1).Select(x =>x.Value).First();
var SQL = (from p in table_list
let test = option_dictionary.Where(x => x.Key == p.IslemID).Select(x => x.Value).First()
select new
{
p.ID,
p.Adi,
test
}
);
}
This method is working in Linq. Its not working in Entity.
Thanks for your help.

LINQ is not the same as LINQ. Your working example uses a data structure in memory, namely List<table> table_list or more generally an IEnumerable<T>. Using the LINQ extension methods of IEnumerable<T> is called LINQ to Objects.
When you apply LINQ to an ObjectSet<T> or DbSet<T> of Entity Framework you are using the LINQ extension methods of IQueryable<T>. In this case you are using LINQ to Entities. They have the same name and you can write the same LINQ expressions like with LINQ to Objects and your code will compile fine.
But the big difference is that a LINQ to Entities query is not executed in memory (like LINQ to Objects) but it has to be translated into SQL to be executed in the database.
If your query is not translatable into SQL or the translation is not supported you get a runtime exception. In your specific case you have a complex in memory data structure - your dictionary - which cannot be used in a SQL query.
You have to rewrite your query to solve the problem. I would use the dictionary after you have executed the query, for example this way:
public class Helper
{
public int id { get; set; }
public int islem { get; set; }
public string textx { get; set; }
// ...
}
using (SerasMacEntity SME = new SerasMacEntity())
{
var SQL = (from p in SME.tbl_admin_islem
orderby p.tarih descending
select new Helper
{
id = p.id,
islem = p.islem,
//...
});
var list = SQL.ToList(); // excutes query in DB, rest happens in memory
foreach (var item in list)
{
item.testx = D.Where(x => x.Key == item.islem)
.Select(x => x.Value)
.FirstOrDefault();
}
Store1.DataSource = list;
Store1.DataBind();
}

I solve it this method;
var SQL = (from p in SME.tbl_admin_islem
orderby p.tarih descending
select new
{
p.id,
p.islem,
p.tarih
}).AsEnumerable().Select(s => new
{
s.id,
s.islem,
s.tarih,
testx = D.Where(x => x.Key == s.islem).Select(x => x.Value).FirstOrDefault()
});
or try this
var SQL = (from p in SME.tbl_admin_islem.AsEnumerable()
orderby p.tarih descending
select p).Select(s => new
{
s.id,
s.islem,
s.tarih,
testx = D.Where(x => x.Key == s.islem).Select(x => x.Value).FirstOrDefault()
});
I was convert my entity AsEnumerable() and then apply again Lambda query.

Related

LINQ merge multiple lists to one list

Let's assume I have multiple db tables, I'll just represent them as lists for convenience:
EntitySource {
public int Id {get; set;}
public ICollection<Entity_1> table_1 { get; set }
public ICollection<Entity_2> table_2 { get; set }
public ICollection<Entity_3> table_3 { get; set }
}
Entity_1/Entity_2/Entity_3 {
public int Id { get; set; }
public string Name { get; set; }
}
List<Entity_1> table1 = new List<Entity_1>() {new Entity_1{Id = 1, Name = "First"}, new Entity_1{Id = 2, Name = "Second"}
List<Entity_2> table2 = new List<Entity_2>() {new Entity_2{Id = 3, Name = "First"}, new Entity_2{Id = 4, Name = "Second"}
List<Entity_3> table3 = new List<Entity_3>() {new Entity_3{Id = 5, Name = "First"}, new Entity_3{Id = 6, Name = "Second"}
I'm querying against EntitySource which contains references to multiple collections that I want to query against and map to MergedList class that contains two properties, Id of the entity source and one collection containing all merged collections of the EntitySource.
What I want to achieve is query for only id's and map them to single list of integers.
Something like this:
var entities = await entitySource.Queryable()
.Select(e => new MergedList()
{
PrincipalId = e.Id,
CombinedIds = e.table1.Select(e => e.Id)
.Concat(e.table2.Select(e => e.Id)
.Concat(e.table3.Select(e => e.Id)
})
.ToListAsync(cancellationToken);
public class MergedList {
public int PrincipalId {get;set;}
public IEnumerable<int> CombinedIds {get;set;}
}
But apparently the above statement is not working, expression could not be parsed.
Unable to translate a collection subquery in a projection since either
parent or the subquery doesn't project necessary information required
to uniquely identify it and correctly generate results on the client
side.
I'm using Entity Framework Core v6.0
You can combine them on the client side.
var filtered = entitySource.Queryable()
.Where(ent => input.Id == ent.Id);
var rawData = await
filtered.SelectMany(e => e.table1.Select(t => new { e.Id, SubId = t.Id } ))
.Concat(filtered.SelectMany(e => e.table2.Select(t => new { e.Id, SubId = t.Id } ))
.Concat(filtered.SelectMany(e => e.table3.Select(t => new { e.Id, SubId = t.Id } ))
.ToListAsync(cancellationToken);
var entities = rawData.GroupBy(x => x.Id)
.Select(g => new MergedList()
{
PrincipalId = g.Key,
CombinedIds = g.Select(x => x.SubId).ToList()
})
.ToList();

Get selected fields on a list using a LINQ query

I have an entity framework generated class like this.
public partial class TBLM_PRODUCT
{
public string PRODUCT_CODE { get; set; }
public string PRODUCT_DESC { get; set; }
public string PRODUCT_ISBN { get; set; }
public string PRODUCT_SUPPLIER { get; set; }
public string PRODUCT_PROGROUP { get; set; }
}
Normally I select items list like this using a LINQ query.
using ( AEntities RAEntity = new AEntities())
{
RAEntity.TBLM_PRODUCT.ToList<DataControllers.TBLM_PRODUCT>();
}
I want to select an item list with two fields like this like as in following query
select PRODUCT_CODE,PRODUCT_DESC from TBLM_PRODUCT where PRODUCT_PROGROUP='GG';
How can I achieve that?
using ( AEntities RAEntity = new AEntities())
{
var all = RAEntity.TBLM_PRODUCT.ToList<DataControllers.TBLM_PRODUCT>();
var yourList = all
.Where(x => x.PRODUCT_PROGROUP == "GG")
.Select(p => new { p.PRODUCT_CODE, p.PRODUCT_DESC })
.ToList();
}
Don't select all records first and then filtered your data.
If you use .ToList<DataControllers.TBLM_PRODUCT>() then it can select all records. So instead of this you can select your columns at the time of query fired to database.
If your TBLM_PRODUCT is of any collection type like IEnumerable<> or IQueryable<> then,
using ( AEntities RAEntity = new AEntities())
{
var result = RAEntity.TBLM_PRODUCT.Where(x => x.PRODUCT_PROGROUP == "GG").Select(x => new { x.PRODUCT_CODE, x.PRODUCT_DESC }).ToList();
}
using (AEntities RAEntity = new AEntities())
{
var list= RAEntity.TBLM_PRODUCT
.Where(p => p.PRODUCT_PROGROUP == "GG")
.Select(p => new TBLM_PRODUCT { PRODUCT_CODE = p.PRODUCT_CODE, PRODUCT_DESC = p.PRODUCT_DESC })
.ToList();
}

Check if a collection contains ALL values from another collection with Deferred Execution

Consider the following classes:
public class Recipe
{
public string Id { get; set; }
public ICollection<RecipeFacet> RecipeFacets { get; set; }
}
public class RecipeFacet
{
public string Id { get; set; }
public Facet Facet { get; set; }
public string RecipeId { get; set; }
}
public class Facet
{
public string Name { get; set; }
}
I need to improve an existing query. I was thinking of using Linq's deferred execution. How would I write a Linq query that returns only Recipes, that contains ALL Facets I specify in a list of Tuples?
This is the original code that loops through Recipes and its Facets. It works but it is slow if my intial results query has lots of Recipes.
IQueryable<Recipe> result; //assume we have data here
string query = "Cuisine:American+Recipe-Type:dinners";
IEnumerable<Tuple<string, string>> taxFacets = query
.Split(' ')
.Select(tf => tf.Split(':'))
.Select(tf => new Tuple<string, string>(tf[0], tf[1]))
.Distinct();
var recipeFacetCollection = result.Select(r => r.RecipeFacets).ToList();
var matchedRecipesIds = new List<string>();
var recIds = result.Select(r => r.Id).ToList();
// initially, include all recipes
matchedRecipesIds.AddRange(recIds);
// loop through each recipe's facet collection
foreach (var col in recipeFacetCollection)
{
// loop through the tax facets from the query
foreach (var tf in taxFacets)
{
var exists = col.Any(f => f.Facet.Name.Equals(tf.Item2, StringComparison.OrdinalIgnoreCase));
// remove any recipe that is missing a facet
if (!exists)
{
matchedRecipesIds.Remove(col.First().RecipeId);
}
}
}
result = result.Where(r => matchedRecipesIds.Contains(r.Id));
How can I have a nice Linq query with deferred execution?
UPDATE::
Turning my Tuple into a List allows me to do this. But this query doesn't return any of my records.
This is my criteria:
Recipes, that have a collection of RecipeFacts, that contains Facets that have Name = "American" AND Name = "dinners".
var listFacets = new List<string>()
{
"American",
"dinners"
};
result = result
.Where(r => r.RecipeFacets
.All(f => !listFacets.Any(t => t.Equals(f.Facet.Name, StringComparison.OrdinalIgnoreCase))));
Your query logic selects all recipes whose facets don't exist in listFacets.
#Hung's logic is closer but selects recipes that have all of their facets in listFacets
I think that you want to select all recipes that contain all listFacets.
Simplifying the example to use lists of strings:
var listFacets = new[] { "a", "d" };
var recipes = new[] { new[] { "a" },
new[] { "a", "d" },
new[] { "a", "d", "e" },
new[] { "x" }
};
// correct query, returns 2 results ad and ade
var result = recipes.Where(r => listFacets.All(f => r.Any(rf => rf == f)));
// original incorrect query, returns x
var result2 = recipes.Where(r => r.All(f => !listFacets.Any(rf => rf == f)));
I am not quite sure cause your code block is quite long but here is what I can come up with
result = result.Where(r => r.RecipeFacets.All(f => taxFacets.Any(t => t.Item1.Equals(f.Facet.Name))));
Let me know if it helps or not
Remove the exclamation from the clause in the check on the listFacets collection.
result = result.Where(r => r.RecipeFacets.All(f => listFacets.Any(t => t.Equals(f.Facet.Name, StringComparison
I got this from #Rimp's help.
WHERE - filter
ALL - Require that All values from listFacets
ANY - is in ANY of the Facets.
result = result
.Where(x => listFacets
.All(lf => x.RecipeFacets
.Any(f => f.Facet.Slug.Equals(lf, StringComparison.OrdinalIgnoreCase))));

Multiple items from .select() linq

I have used a lot of SQL in the past but am new to LINQ. I have the following query which selects the otherID from the relevant table successfully, however when I try to select multiple columns I am unable to do so.
This is my following query:
var getQ = db.Requests.Where(x => temp.Contains(x.carID)).Select(x => x.otherID).ToList();
I have tried
var getQ = db.Requests.Where(x => temp.Contains(x.carID)).Select(x => x.otherID && x.dayID).ToList();
I am unable to get it to work, any help appreciated, thanks
You can use anonymous type to return multiple columns
var getQ = db.Requests.Where(x => temp.Contains(x.carID))
.Select(x => new { OtherID = x.otherID, DayID = x.dayID).ToList();
You can make a custom class, as the anonymous type could not be returned from method.
class YourClass
{
public int OtherID { get; set; }
public int DayID { get; set; }
}
var getQ = db.Requests.Where(x => temp.Contains(x.carID))
.Select(x => new YourClass { OtherID = x.otherID, DayID = x.dayID).ToList();
make the change is the select statement:
var getQ = db.Requests.Where(x => temp.Contains(x.carID)).Select(x => new{x.otherID, x.dayID}).ToList();

Converting list returned through LINQ to list of class objects

I got a list using LINQ-to-SQL:
var query = studentRankTable
.AsEnumerable()
.GroupBy(r =>
new
{
Name = r.Field<string>("ID"),
Action = r.Field<string>("Name")
})
.Select(grp =>
new
{
Name = grp.Key.Name,
Action = grp.Key.Action,
Count = grp.Count()
});
query = query.ToList();
The end value of the query is:
[0] { Name = "831001", Action = "Login", Count = 8 } <Anonymous Type>
[1] { Name = "810030", Action = "Game Map Visit", Count = 4 } <Anonymous Type>
Now I have to convert this into a class that I have defined:
[DataContract]
public class StudentRank
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Count { get; set; }
[DataMember]
public string Action { get; set; }
}
I am not able to use foreach because it has datatype of anonymous
How can I convert this list to a list of StudentRank objects?
You can simply use the StudentRank class in Select clause of LINQ:
var query = studentRankTable
.AsEnumerable()
.GroupBy(r =>
new
{
Name = r.Field<string>("ID"),
Action = r.Field<string>("Name")
})
.Select(grp =>
new StudentRank
{
Name = grp.Key.Name,
Action = grp.Key.Action,
Count = grp.Count()
});
This way return type of this query will be IQueryable<StudentRank> so ToList() will return List<StudentRank> which can be easily used.
There's actually nothing stopping you from using foreach if you use a var iterator
foreach(var s in result)
{
...
}
This auto-types s and works even for anonymous types
Also, Select would work here
query = query.Select(s => new Student { Name = s.Name, Action = s.Action, Count = s.Count });
Finally, if you pull into an actual list, there is the List.ForEach method
You could try this one in your select:
Select(grp => new StudentRank
{
Name = grp.Key.Name,
Action = grp.Key.Action,
Count = grp.Count()
});
This way instead of creating an object of anonymous type foreach item in your sequence, you create an object of type StudentRank foreach item in your sequence.
Furthermore, If you want only to iterate through the elements of your query's result, you don't have to call the ToList().
You could achieve that you want as easy as the following:
foreach(var item in items)
where I have called the result of your query as items, in order to be more meaningfull.

Categories