Simple SELECT WHERE LINQ Query to a list - c#

I am new to LINQ,
I want to generate a list of objects from my dbcontext where a certain field is set to true.
This is what I have so far, but I am getting an error about a select?
using (var db = new dbContext())
{
return (from s in db.sims.Where(x=>x.has_been_modified == true) select x).ToList();
}
EDIT:
//Returns a list of entries which where marked as edited in the sim managment database
private List<String> GetUpdatedEntries()
{
using (var db = new dbContext())
{
return db.sims.Where(x => x.has_been_modified).ToList();
}
}

select s, not x and this will work. (because you do from s)
shorter way
return db.sims.Where(x => x.has_been_modified).ToList();
For your Edit
the method return type should be a List<Sim>, not a List<String>

This will work
return db.sims.Where(x=>x.has_been_modified).ToList();
method Linq looks cleaner here
you don't need to check your bool against true
in your previous answer you used s as context and selected x, changing to select s should work also
Consider using lazy loading and don't add ToList at the end of every query

Related

using linq Query how can i update multipul Records

Here im getting Multipul values as 1,2,3 for ENQUIRY_CODE
public void HRUpdateStatus(string ENQUIRY_CODE, int uid)
{
var x = (from e in db.EMS_ENQUIRYREGISTRATION_MASTER
where e.ENQUIRY_CODE == ENQUIRY_CODE
select e).ToList();
foreach (var abc in x)
{
abc.HRowner = uid;
db.SaveChanges();
}
...
}
Please help me where im doing mistake
A LINQ statement will never change the source sequence.
LINQ is not meant to do that.
The proper solution depends on which kind of DbContext you are using. If you use entity framework you'll have to fetch the items before you can update one or more of the properties.
In your case, you want to change one property of all fetched values to the same new value. Consider creating an extension function for your DbContext. See extenstion methods demystified
The following takes an IQueryable sequence of some source class (TSource), and an action that should be performed on each source element.
public void ForEach<TSource>(this IQueryable<TSource> source,
Action<TSource> action)
{
var fetchedItems = source.ToList();
foreach (var fetchedItem in fetchedItems)
{
action(fetchedItem);
}
}
Usage:
using (var dbContext = new MyDbContext())
{
db.EMS_ENQUIRYREGISTRATION_MASTER
.Where (registrationMaster => registrationMaster.ENQUIRY_CODE == ENQUIRY_CODE)
.ForEach(registrationMaster => registrationMaster.HRowner = uid);
db.SaveChanges();
}
I chose to return void instead of IEnumerable<TSource> to indicate to users of the function that the queried data is materialized and might have been changed. After all the following might have been confusing:
IQueryable<Student> students = ...
var updatedStudents = students.ForEach(student => student.Grades.Add(new Grade(...))
.Take(2)
.ToList();
You want to communicate that all students are updated, not just the 2. Consider returning an IReadonlyList<TSource> or similar, so you don't have to materialize the data again.
I think this is what you mean:
var codes = ENQUIRY_CODE.Split(',').ToList();
var x= db.EMS_ENQUIRYREGISTRATION_MASTER.Where(s => codes.Contains(s.ENQUIRY_CODE)).ToList();

Can't use .ToList() with IQueryable<T> [duplicate]

I'm migrating some stuff from one mysql server to a sql server but i can't figure out how to make this code work:
using (var context = new Context())
{
...
foreach (var item in collection)
{
IQueryable<entity> pages = from p in context.pages
where p.Serial == item.Key.ToString()
select p;
foreach (var page in pages)
{
DataManager.AddPageToDocument(page, item.Value);
}
}
Console.WriteLine("Done!");
Console.Read();
}
When it enters into the second foreach (var page in pages) it throws an exception saying:
LINQ to Entities does not recognize the method 'System.String
ToString()' method, and this method cannot be translated into a store
expression.
Anyone know why this happens?
Just save the string to a temp variable and then use that in your expression:
var strItem = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == strItem
select p;
The problem arises because ToString() isn't really executed, it is turned into a MethodGroup and then parsed and translated to SQL. Since there is no ToString() equivalent, the expression fails.
Note:
Make sure you also check out Alex's answer regarding the SqlFunctions helper class that was added later. In many cases it can eliminate the need for the temporary variable.
As others have answered, this breaks because .ToString fails to translate to relevant SQL on the way into the database.
However, Microsoft provides the SqlFunctions class that is a collection of methods that can be used in situations like this.
For this case, what you are looking for here is SqlFunctions.StringConvert:
from p in context.pages
where p.Serial == SqlFunctions.StringConvert((double)item.Key.Id)
select p;
Good when the solution with temporary variables is not desirable for whatever reasons.
Similar to SqlFunctions you also have the EntityFunctions (with EF6 obsoleted by DbFunctions) that provides a different set of functions that also are data source agnostic (not limited to e.g. SQL).
The problem is that you are calling ToString in a LINQ to Entities query. That means the parser is trying to convert the ToString call into its equivalent SQL (which isn't possible...hence the exception).
All you have to do is move the ToString call to a separate line:
var keyString = item.Key.ToString();
var pages = from p in context.entities
where p.Serial == keyString
select p;
Cast table to Enumerable, then you call LINQ methods with using ToString() method inside:
var example = contex.table_name.AsEnumerable()
.Select(x => new {Date = x.date.ToString("M/d/yyyy")...)
But be careful, when you calling AsEnumerable or ToList methods because you will request all data from all entity before this method. In my case above I read all table_name rows by one request.
Had a similar problem.
Solved it by calling ToList() on the entity collection and querying the list.
If the collection is small this is an option.
IQueryable<entity> pages = context.pages.ToList().Where(p=>p.serial == item.Key.ToString())
Hope this helps.
Upgrading to Entity Framework Version 6.2.0 worked for me.
I was previously on Version 6.0.0.
Hope this helps,
Change it like this and it should work:
var key = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == key
select p;
The reason why the exception is not thrown in the line the LINQ query is declared but in the line of the foreach is the deferred execution feature, i.e. the LINQ query is not executed until you try to access the result. And this happens in the foreach and not earlier.
If you really want to type ToString inside your query, you could write an expression tree visitor that rewrites the call to ToString with a call to the appropriate StringConvert function:
using System.Linq;
using System.Data.Entity.SqlServer;
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
using System;
namespace ToStringRewriting {
class ToStringRewriter : ExpressionVisitor {
static MethodInfo stringConvertMethodInfo = typeof(SqlFunctions).GetMethods()
.Single(x => x.Name == "StringConvert" && x.GetParameters()[0].ParameterType == typeof(decimal?));
protected override Expression VisitMethodCall(MethodCallExpression node) {
var method = node.Method;
if (method.Name=="ToString") {
if (node.Object.GetType() == typeof(string)) { return node.Object; }
node = Call(stringConvertMethodInfo, Convert(node.Object, typeof(decimal?));
}
return base.VisitMethodCall(node);
}
}
class Person {
string Name { get; set; }
long SocialSecurityNumber { get; set; }
}
class Program {
void Main() {
Expression<Func<Person, Boolean>> expr = x => x.ToString().Length > 1;
var rewriter = new ToStringRewriter();
var finalExpression = rewriter.Visit(expr);
var dcx = new MyDataContext();
var query = dcx.Persons.Where(finalExpression);
}
}
}
In MVC, assume you are searching record(s) based on your requirement or information.
It is working properly.
[HttpPost]
[ActionName("Index")]
public ActionResult SearchRecord(FormCollection formcollection)
{
EmployeeContext employeeContext = new EmployeeContext();
string searchby=formcollection["SearchBy"];
string value=formcollection["Value"];
if (formcollection["SearchBy"] == "Gender")
{
List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Gender == value).ToList();
return View("Index", emplist);
}
else
{
List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Name == value).ToList();
return View("Index", emplist);
}
}
I got the same error in this case:
var result = Db.SystemLog
.Where(log =>
eventTypeValues.Contains(log.EventType)
&& (
search.Contains(log.Id.ToString())
|| log.Message.Contains(search)
|| log.PayLoad.Contains(search)
|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
)
)
.OrderByDescending(log => log.Id)
.Select(r => r);
After spending way too much time debugging, I figured out that error appeared in the logic expression.
The first line search.Contains(log.Id.ToString()) does work fine, but the last line that deals with a DateTime object made it fail miserably:
|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
Remove the problematic line and problem solved.
I do not fully understand why, but it seems as ToString() is a LINQ expression for strings, but not for Entities. LINQ for Entities deals with database queries like SQL, and SQL has no notion of ToString(). As such, we can not throw ToString() into a .Where() clause.
But how then does the first line work? Instead of ToString(), SQL have CAST and CONVERT, so my best guess so far is that linq for entities uses that in some simple cases. DateTime objects are not always found to be so simple...
My problem was that I had a 'text' data type for this column (due to a migration from sqlite).
Solution: just change the data type to 'nvarchar()' and regenerate the table.
Then Linq accepts the string comparison.
I am working on retiring Telerik Open Access and replacing it with Entity Framework 4.0. I came across same issue that telerik:GridBoundColumn filtering stopped working.
I find out that its not working only on System.String DataTypes. So I found this thread and solved it by just using .List() at the end of my Linq query as follows:
var x = (from y in db.Tables
orderby y.ColumnId descending
select new
{
y.FileName,
y.FileSource,
y.FileType,
FileDepartment = "Claims"
}).ToList();
Just turn the LINQ to Entity query into a LINQ to Objects query (e.g. call ToArray) anytime you need to use a method call in your LINQ query.

Pivot List of entities using LINQ in C#

What I have is a list of entities coming back from a database that I want to pivot so that I end up with a new list of entities with the duplicates removed and the pivoted items attached to the new entity.
Currently I have a simple solution like this:
IQueryable<Entity> results // being passed in from calling method.
List<Entity> pivotedEntities = new List<Entity>();
foreach (Entity entity in results)
{
if (pivotedEntities.Contains(entity))
{
Entity matchedEntity = pivotedEntities.Find(e => e.Id == entity.Id);
matchedEntity.RelatedEntities.Add(entity.RelatedEntity);
}
else
{
pivotedEntities.Add(new Entity());
}
}
return pivotedEntities.AsQueryable();
This works fine however I want to be able to achieve the same thing with a LINQ query on the IQueryable results variable so that it maintains its deffered execution rather than executing as soon as I enter the foreach.
I have other methods that get called around this code that also alter the IQueryable and I then want to execute the call to the database once all filters have been applied.
Hope that all makes sense.
Maybe this will reduce few loops.
List<Entity> pivotedEntities = new List<Entity>();
int index = 0;
foreach (Entity entity in results)
{
index = pivotedEntities.IndexOf(e => e.Id == entity.Id);
if (index>-1)
{
pivotedEntities[index].RelatedEntities.Add(entity.RelatedEntity);
}
else
{
pivotedEntities.Add(new Entity());
}
}
return pivotedEntities.AsQueryable();

Complex object in grid view

I have a gridview, the datasource of which is the following function:
public static List<Train> GetTrainsByIDs(int [] ids) {
using (var context = new MyEntities())
{
return ids.Select(x => context.Trains.Single(y => y.TrainID ==x)).AsQueryable().Include(x=>x.Station).ToList();
}
}
The grid view has an ItemTemplate of <%# Eval("Station.Name") %>.
This causes the error The ObjectContext instance has been disposed and can no longer be used for operations that require a connection despite the fact that I used the include method.
When I change the function to
public static List<Train> GetTrainsByIDs(int [] ids) {
using (var context = new MyEntities())
{
return context.Trains.Where(x => ids.Contains(x.TrainID)).Include(x=>x.Station).ToList();
}
}
it works fine, but then they come out in the wrong order, and also if I have 2 ids the same I would like 2 identical trains in the list.
Is there anything I can do other than create a new viewmodel? Thank you for any help
As for the first query: that's deferred execution.You created an IEnumerable of Trains, noticed that it did not have the Include method, so cast it to IQueryable, added the Include and added the ToList() to prevent lazy loading.
But As per MSDN on DbExtensions.Include:
This extension method calls the Include(String) method of the IQueryable source object, if such a method exists. If the source IQueryable does not have a matching method, then this method does nothing.
(emphasis mine)
The result of the select is an IEnumerable converted to IQueryable, but now implemented by EnumerableQuery which does not implement Include. And nothing happens.
Now the data enters the grid which tries to display the station, which triggers lazy loading while the context is gone.
Apart from that, this design has another flaw: it fires a query for each id separately.
So the second query is much better. It is one query, including the Stations. But now the order is dictated by the order the database pleases to return. You could use Concat to solve this:
IQueryable<Train> qbase = context.Trains.Include(x=>x.Station);
IQueryable<Train> q = null;
foreach (var id in ids)
{
var id1 = id; // Prevent modified closure.
if (q == null)
q = qbase.Where(t => t.Id == id1);
else
q = q.Concat(qbase.Where (t => t.Id == id1));
}
The generated query is not very elegant (to say the least) but after all it is one query as opposed to many.
After reading #Gert Arnold's answer, and getting the idea of doing it in 2 stages, I managed very simply using the first query like this:
using (context = new MyEntities())
{
var trns = context.Trains.Include(x => x.Station);
return ids.Select(x => trns.Single(y => y.TrainID == x)).ToList();
}

Using LINQ in an Update Method - trouble with where clause

I'm writing an update method that passes in a list of objects to be updated, I'm wondering how I would write a LINQ query to grab all the objects from the database that need to be updated
This is an example of my update method with the linq query that I'm trying to make (pseudo-code used for the part I don't know how to do)
void UpdateObjects(List<MyObjects> updatedObjects)
{
DatabaseContext myContext = new DatabaseContext();
var originalObjectsThatRequireUpdating = from o in myContext.MyObjects
where o.ID matches one of updatedObjects.ID
select o;
foreach (var originalObject in originalObjectsThatRequireUpdating )
{
IEnumerable<MyObjects> tmpItem = updatedObjects.Where(i => i.ID == originalObject.ID);
originalObject.Field1 = tmpItem.ToList()[0].Field1;
//copy rest of the fields like this
}
myContext.SubmitChanges();
}
I don't know how to create a linq query easily with something like
where o.ID matches one of updatedObjects.ID
also if someone knows an easier way to accomplish what I'm doing please tell, this seems sort of like an odd way to do it, but was the only way I can think of / know how to do at this point.
you can do that with:
where updatedObjects.Any(uo => uo.ID == o.ID)
You should be looking to implement batch updates with linq for example like it's described at http://www.aneyfamily.com/terryandann/post/2008/04/Batch-Updates-and-Deletes-with-LINQ-to-SQL.aspx
You could create a lambda or another method that performs the check for you; for example
where IDMatches(o.ID, updatedObjects)
and then define IDMatches as a simple iteration over updatedObjects.
static void IDMatches(int id, List<MyObject> updatedObjects)
{
foreach (MyObject updated in updatedObjects)
{
if (id == updated.ID)
return true;
}
return false;
}

Categories

Resources