John
John

Reputation: 3945

cannot apply indexing with [] to an expression

 var dbPerson = from p in db.People 
                where p.Id == PersonId select p;
 dbPerson[0].HolidaysRemaining--;

is throwing me an error with dbPerson[0] saying cannot apply indexing with [] to an expression of type 'system.linq.lqueryable,holidayBookingApp.model.person>

can someone please advise how I can resolve this?

Thanks

Upvotes: 3

Views: 13644

Answers (4)

SalientBrain
SalientBrain

Reputation: 2541

You should understand the idea behind the Linq & IEnumerable (& IQueryable) interface. IEnumerable used for lazy loading of sequences, so if you create an extension method for loop like this:

public static IEnumerable<T> LazyForEach<T>(this IEnumerable<T> source, Action<T> action) //action to perform                
        {
            if (action == null) throw new ArgumentNullException("action");
            foreach (T element in source)
            {
                action(element);
                yield return element;
            }
        }

and try to use LazyForEach in IEnumerable-returning method (Linq) chain:

db.People.Where(p=>p...).LazyForEach(p=>
{
   MessageBox.Show(p.ToString());
});

your code in provided action will not execute until you force enumeration (maybe partial) with ToList/ToArray/ElementAt/First/Last/Any/Take/Skip ... or you can create alt. extension:

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            if (source == null)
                return null;
            if (action == null) throw new ArgumentNullException("action");
            //var sourceList = source.ToList(); //forcing enumeration
            var sourceList = new List<T>();
            foreach (var element in source)
            {
                action(element);
                sourceList.Add(element);
            }
            return sourceList;
        }

Upvotes: 1

Michael Edenfield
Michael Edenfield

Reputation: 28338

The result of your LINQ query is not a List, it's a custom type of IQueryable that does not have an indexer. You cannot get random access to the results of a LINQ query in that form.

You have multiple options if you really need that:

  • Convert it to something that implements IList, e.g. call dbPerson.ToList().
  • If you really need just the first element, use the IQueryable extension method for that purpose: dbPerson.First()
  • If you want an arbitrary element as [x], use the IQueryable extension method for that purpose: dbPerson.Skip(x).First()

Upvotes: 5

andrewpey
andrewpey

Reputation: 650

It's because dbPerson is IEnumerable, what doesn't support indexing concept. You can use some Linq methods, like dbPerson.First(), or simply convert it to List:

var list = dbPerson.ToList();
list[0].HolidaysRemaining--;

Upvotes: 2

Rawling
Rawling

Reputation: 50104

To get the first item that your query dbPerson returns, use

var firstPerson = dbPerson.First();

or Single if you only expect one match and want an exception to be thrown if this expectation is broken.

However, I'm not convinced firstPerson.HolidaysRemaining--; will change anything in your database without further code:

var dbPeopleWithThisId = from p in db.People 
                         where p.Id == PersonId
                         select p;
var specificPerson = dbPeopleWithThisId.Single();
specificPerson.HolidaysRemaining--;
db.SaveChanges(); // Thanks to J. Steen

Upvotes: 4

Related Questions