14

Given the following simplified Entity Framework 6 context, I am trying to populate a List with the entities but having problems with how to cast (I believe) via reflection.

public class FooContext : DbContext
{
   public virtual IDbSet<FooClass> Foo { get; set; }    
   //...
}

public class FooClass
{
    public int Id{ get; set; }
    public string Name {get; set; }
    //...    
}

public main()
{
     using (var context = new FooContext())
     {
         var sets = typeof(FooContext).GetProperties().Where(pi => pi.PropertyType.IsInterface && pi.PropertyType.GetGenericTypeDefinition().ToString().ToLower().Contains("idbset"));

         foreach (var set in sets)
         {
             //When I debug and enumerate over 'value' the entire results are shown so I believe the reflection part is OK.
             var value = set.GetValue(context, null);

             //Always returns null. How can I cast DbSet<T> to List<object> or List<T>? 
             var list = value as List<object>();

             //...
         }
     }
}

I'm doing this for utility method for some integration testing I am doing. I am trying to do this without using direct inline SQL calls (using SqlConnection and SqlCommand etc) to access the database (as the datastore may change to Oracle etc).

Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
Kyle
  • 951
  • 3
  • 14
  • 31
  • 1
    You can cast to `IEnumerable` interface – Alexey Nis Jun 15 '15 at 12:50
  • `set.GetValue(context, null)` returns an `object`.You're trying to cast it to `List`. – Amit Kumar Ghosh Jun 15 '15 at 12:52
  • 2
    A `DbSet<>` *is not a list*, and neither a `DbSet` nor a `List` is a `List`. What you are trying to do is doomed. Can you clarify your intent? What is it that you want to *do*? – Marc Gravell Jun 15 '15 at 12:52
  • @AmitKumarGhosh well, to be fair, that would work *if it was one* – Marc Gravell Jun 15 '15 at 12:53
  • `DbSet` doesn't inherit from `List` or `List` so you can't just cast it. Why do you want a list? Why not just enumerate the `DbSet`? Why are you using reflection anyway? – Charles Mager Jun 15 '15 at 12:53
  • What are you trying to do? Why are you using reflection on a `DbSet`? – Yuval Itzchakov Jun 15 '15 at 12:54
  • 2
    DbSet{T} implements IEnumerable{T}. List{T} has a constructor which takes an IEnumerable{T}, so you could just do `new List(dbSet)` – Jaanus Varus Jun 15 '15 at 12:56
  • 1
    Your type check should probably be `pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>)` – Lee Jun 15 '15 at 12:56
  • @Lee note you must check `IsGenericType` before calling that – Marc Gravell Jun 15 '15 at 12:57
  • @MarcGravell - Thanks, forgot about that. – Lee Jun 15 '15 at 12:59
  • Doing "as IEnumerable" works. FYI the purpose of the integration test is for testing the repository. Inside the repository it using EF6 which in this case is connecting to SQL. However it in the future it could change to Oracle or XML or whatever. I am basically doing lots of integration tests that ensure that values passed into the repository (Creates, Updates or deletes) are 1) getting updated in the database. (as the models I have are quiet complex) 2) only the relevant fields on the entity getting saved are getting edited 3) That no unexpected changes are happening to other entitie – Kyle Jun 15 '15 at 13:02
  • Doing it dynamically via reflection saves tying my unit tests too closely to my actual implementation. Also I cant access the context.ChangeTracker because its inside the repository. I also dont want to Shim this out via Microsoft Fakes as it is OTT. – Kyle Jun 15 '15 at 13:06

4 Answers4

14

IDBSet inherits from IQueryable<TEntity>, IEnumerable<TEntity>, IQueryable, and IEnumerable, so you can't directly cast it to a list that way. You could get a List<TEntity> of all entities in the DBSet though by using .ToList() or .ToListAsync()

THis creates a copy of all entities in memory though, so you should consider operating with LINQ directly on the DBSet

Alex Sikilinda
  • 2,928
  • 18
  • 34
LInsoDeTeh
  • 1,028
  • 5
  • 11
12
//dont forget using System.Linq;
using (var context = new FooContext())
{
   IQueryable<FooClass> rtn = from temp  in context.Foo select temp;
   var list = rtn.ToList();
}
Gonzalo.-
  • 12,512
  • 5
  • 50
  • 82
VicYam
  • 121
  • 1
  • 9
  • I had a parsing error trying to retreive all elements in a table. Sending a list instead of a "IQueryable" solved the issue. – BorisD Aug 25 '19 at 09:18
6

Alongside VicYam's answer, here is an easier way with a detailed explanation.

Once you add the System.Linq namespace, you no longer need to get IQueryable and then convert to a List. Instead, you will get the extension methods on the DbSet object.

What does this mean? You can simply return the DbSet by itself as it inherits from IEnumerable. The consumer, possibly a dev, can then do a .ToList or any other list type they may need.

Easiest

This will return the DbSet as is, which already inherits from IEnumerable which is a list type that can be then converted to a List.

List<ObjectType> list = new List<ObjectType>();
using (var context = new FooContext())
{
    list = context.Foo;
}

Alternative

You can immediately convert from IEnumerable to a List.

using (var context = new FooContext())
{
    var list = context.Foo.ToList();
}

Still want VicYam's answer but as a one line?

using (var context = new FooContext())
{
    var list = context.Foo.AsQueryable().ToList();
}
AzzamAziz
  • 2,144
  • 1
  • 24
  • 34
-1
private StudentDatabaseEntities db = new StudentDatabaseEntities();

public List<StudentDatabaseDbTableModel> AllProducts()
{
    return db.StudentDatabaseDbTableModel.ToList();
}   

db.StudentDatabaseDbTableModel is of type DbSet. ToList is a method inside DbSet class. ToList method converts object of type DbSet to List type.

Siddarth Kanted
  • 5,738
  • 1
  • 29
  • 20
  • While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – DimaSan Mar 07 '17 at 11:05
  • 2
    There is no such a `ToList()` method in the DbSet. – Bassem Dec 19 '17 at 07:17