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();
Related
I am trying to remove duplicate code throughout my project and I am at a standstill trying to figure this out. What I am trying to do is create a base linq query that will be reused to add things like Where, Take...etc in multiple different methods.
public IQueryable<Object> FooLinq(int id)
{
using (var ctx = new dbEntities())
{
var results =
(from account in ctx.account
join memberProducts in ctx.tblMemberProducts on account.Id equals memberProducts.AccountId
orderby account.date descending
select new{account,memberProducts}).ToList();
return results;
}
}
So that would be by base query above and I would have a seperate method that would reuse VioLinq but this time would use a where clause in it.
public List<IncomingViolations> Foo1(int id)
{
//Linq query FooLinq() where Name == "Bob"
}
You'll need to do two things:
Return the query prior to materializing it.
Make sure the context is still in scope when the final query is materialized.
These two requirements will play off each other somewhat, and there are a number of approaches you can take to meet them.
For example, you could make your method take the context as a parameter, forcing the caller to provide it and manage its lifecycle.
public IQueryable<AccountInfo> FooLinq(DbEntities ctx, int id)
{
return
from account in ctx.account
orderby account.date descending
select new AccountInfo()
{
Name = account.Name,
Mid = account.MemberID,
Date = account.Date,
Address = account.Address,
};
}
public List<IncomingViolations> Foo1(int id)
{
using(var ctx = new dbEntities())
{
//Linq query FooLinq() where Name == "Bob"
return FooLinq(ctx).Where(v => v.Name == "Bob").ToList();
}
}
You could alternatively inject the context as a constructor-injected dependency, and use a DI framework to manage the context's lifecycle.
You can do it as Queryable then add conditions to it.
For example:
public List<account> GetAccountsByName(string name, bool usePaging, int offset = 0, int take = 0) {
var query = GetMyQuery();
query = query.Where(x => x.Name == name);
query = query.OrderBy(x => x.Name);
if(usePaging) {
query = query.Take(take).Skip(offset);
}
query = PrepareSelectForAccount(query);
return query.ToList(); .
}
public IQueryable<account> GetMyQuery(){
return ctx.account.AsQueryable();
}
public IQueryable<account> PrepareSelectForAccount(IQueryAble<account> query){
return query.Select(select new AccountInfo()
{
Name = account.Name,
Mid = account.MemberID,
Date = account.Date,
Address = account.Address,
}
);
}
Sure, but don't call .ToList(), and return IQueryable<T> instead of List<T>. LINQ is based on the concept of deferred execution which means the query is not actually performed until the enumerable is iterated over. Until then, all you have done is built an object which knows how to do the query when the time comes.
By returning an IQueryable<T> from a function that sets up the "basic query," you are then free to tack on additional LINQ methods (such as .Where() or .Take()) to produce a modified query. At this point you are still simply setting up the query; it is actually performed only when you iterate over the enumerable, or call something like .ToList() which does that for you.
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
I have this LINQ query:
List<Customers> customers = customerManager.GetCustomers();
return customers.Select(i => new Customer {
FullName = i.FullName,
Birthday = i.Birthday,
Score = i.Score,
// Here, I've got more fields to fill
IsVip = DetermineVip(i.Score)
}).ToList();
In other words, I only want one or two fields of the list of the customers to be modified based on a condition, in my business method. I've got two ways to do this,
Using for...each loop, to loop over customers and modify that field (imperative approach)
Using LINQ projection (declarative approach)
Is there any technique to be used in LINQ query, to only modify one property in projection? For example, something like:
return customers.Select(i => new Customer {
result = i // telling LINQ to fill other properties as it is
IsVip = DetermineVip(i.Score) // then modifying this one property
}).ToList();
you can use
return customers.Select(i => {
i.IsVip = DetermineVip(i.Score);
return i;
}).ToList();
Contrary to other answers, you can modify the source content within linq by calling a method in the Select statement (note that this is not supported by EF although that shouldn't be a problem for you).
return customers.Select(customer =>
{
customer.FullName = "foo";
return customer;
});
You "can", if you create a copy constructor, which initializes a new object with the values of an existing object:
partial class Customer
{
public Customer(Customer original)
{
this.FullName = original.FullName;
//...
}
}
Then you can do:
return customers.Select(i => new Customer(i) { IsVip = DetermineVip(i.Score)})
.ToList()
But the downfall here is you will be creating a new Customer object based on each existing object, and not modifying the existing object - this is why I have put "can" in quotes. I do not know if this is truly what you desire.
No, Linq was designed to iterate over collections without affecting the contents of the source enumerable.
You can however create your own method for iterating and mutating the collection:
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach(T item in enumeration)
{
action(item);
}
}
You can then use as follows:
return customers.ToList()
.ForEach(i => i.IsVip = DetermineVip(i.Score))
.ToList();
Note that the first ForEach will clone the source list.
As customers already is a List, you can use the ForEach method:
customers.ForEach(c => c.IsVip = DetermineVip(c.Score));
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();
}
We have a list of strings and we need to filter our results by that list. Example would be find all students who have SSNs that start with 465, 496, or 497 (plus x more)
List<string> list = GetPossibleStartsWithValues();
var qry = from student in entities.Students.WhereStartsWith(x=>x.SSN, list)
select new SearchedStudent
{
Name = student.Name,
SSN = student.SSN,
...
}
The code provided here is close to what we need, but we can't figure out how to impliment the StartsWith that we need using the Expression Class.
Well, you could try this:
public static IQueryable<T> WhereStartsWith<T>(this IQueryable<T> source,
Expression<Func<T, string>> projection,
List<T> list)
{
return source.Where(x => list.Any(y => projection(x).StartsWith(y)));
}
That may well not work, but it would be worth trying before you go into anything more complicated.
EDIT: As you say, the above won't compile - you basically need to build an expression tree representing the bit within the Where clause. Oops. However, before you start doing that, it would be worth seeing whether it'll work in the end. Try this:
List<string> list = GetPossibleStartsWithValues();
var qry = from student in entities.Students
.Where(student => list.Any(y => student.SSN.StartsWith(y)))
select new SearchedStudent
{
Name = student.Name,
SSN = student.SSN,
...
}
If that doesn't work, then making a more general method won't be any use :(
How about using a compound statement such as
var qry = from student in entities.Students.Where(
s => list.Where( x => s.StartsWith(x)).Count() != 0 )