Looping over derived DbContext DbSets so I can add a ClearAll() extension to my DbContext object
Asked Answered
B

1

1

Based on [the difference between Type.IsGenericType and Type.IsGenericTypeDefinition][1], I gained the piece of information I was missing in order to be able to retrieve a DbContext's DbSets via Reflection.

However, I am now stuck somewhere else. In the code sample below, I do succeed in obtaining the DbSet generic instances, but I now want to be able to cast them at compile time, to the specific generic type defintion.

dbSet is a real instance of one of the DbSets<...> from my DbContext, but how to cast it to its real type definition ? (Take the 1st loop iteration, dBSet will represent DbSet - how to enforce this type at compile time upon this variable ?


Update: I have just reviewed what I am trying to do and... am afraid it makes no sense/it is not possible. Since the real types are discovered only at runtime, there is no way I can, prior to that (and compile time is a stage in time prior to that) relate to the real generic types.

In any case - what I am really interested to is to have, at compile time, the IDE showing me members of IEnumerable<T> (DbSet<> implements it). So I really need to cast it to DbSet<>. How does such a cast should look like ?

Is it possible ?!

private static void Main(string[] args)
{
    MyDb myDb = new MyDb();

    List<PropertyInfo> dbSetProperties = myDb
        .GetType()
        .GetProperties()
        .Where(pi => pi.PropertyType.IsGenericType && string.Equals(pi.PropertyType.GetGenericTypeDefinition().FullName, typeof(DbSet<>).FullName, StringComparison.OrdinalIgnoreCase)).ToList();

    foreach (PropertyInfo dbSetProperty in dbSetProperties)
    {
        Type[] typeArguments = dbSetProperty.PropertyType.GetGenericArguments();
        Type dbSetGenericContainer = typeof(DbSet<>);
        Type dbSetGenericType = dbSetGenericContainer.MakeGenericType(typeArguments);
        object dbSet = Convert.ChangeType(dbSetProperty.GetValue(myDb), dbSetGenericType);
    }
}

public class MyDb : DbContext
{
    public DbSet<A> A { get; set; }
    public DbSet<B> B { get; set; }

    public void ClearTables()
    {
    }
}

public class A
{
    public string aaa { get; set; }
    public List<int> myList { get; set; }
}

public class B
{
    public int MyInt { get; set; }
}
Burr answered 2/8, 2015 at 11:51 Comment(7)
Use pi.PropertyType.IsGenericTypeCrimpy
@UlugbekUmirov: you are right... I am now wondering how the guy in the other post gets his results...Burr
@Veverke: Thanks for finding this error. In my answer, it has been corrected by dasblinkenlight in the meantime!Plated
@DanielHilgarth: oh, great, I was puzzled with that post :) I guess I should then delete this post?Burr
No need to delete it.Plated
Well I changed it then, so it has real use.Burr
DbSet<> is not a type; it's a type constructor that generates concrete types like DbSet<YourClass>. Your question still doesn't make sense.Disputant
D
1

DbSet<> itself is not a type; your question doesn't actually make sense.

However, luckily for you, DbSet<T> implements the non-generic DbSet base class, so you can just use that instead.

Disputant answered 4/8, 2015 at 14:17 Comment(2)
I can do DbSet dbSet = Convert.ChangeType(dbSetProperty.GetValue(myDb), dbSetGenericType) as DbSet; but what I am really after is a way to remove all elements of each DbSet, I wanted to add a ClearAll functionality to the DbContext. I do not see DbSet providing me anything that can help me with this. I try making the DbSet AsQueryable, but I do not see how this can help me either. I need something like AsEnumerable()Burr
@Veverke: Convert.ChangeType is completely useless to you; it has nothing to do with this situation. Instead, you can make a generic method that takes DbSet<T> and use Reflection to call it with the correct T.Disputant

© 2022 - 2024 — McMap. All rights reserved.