简体   繁体   中英

How to iterate through an ICollection type property with reflection

The title covers a very tiny part of what I'm trying to achieve, so be informed ahead. I'm trying to build a generic way of properly updating collection properties of an entity when that entity itself is updated. In the nutshell I want to do something similar to the approach explained here but I want to go generic way. For that I have created an attribute called EntityCollectionPropertyAttribute and marked those properties of entities that I need to be updated too. Here's an example:

   public class Teacher{
      public int TeacherId{get;set;}
      public string Name{get;set;}
   }

   public class Student{
      public int StudentId{get;set;}
      public string Name {get;set;}
      [EntityCollectionProperty]
      public virtual ICollection<Teacher> Teachers{get;set;}
   }


 public bool IsPropertyAnEntityCollection(PropertyInfo prop){
     return Attribute.IsDefined(prop, typeof(EntityCollectionPropertyAttribute));
 }

 public void Update<T>(T entity)where T:class{
    DbEntityEntry entry = MyDbContext.Entry(entity);
    foreach (var prop in entry.Entity.GetType().GetProperties())
    {
        if(IsPropertyAnEntityCollection(prop)){
            //Here's where I get stuck
        }
    }
 }

Lets say the parent entity that has been updated is a Student. Besides Name (and possibly ID) properties, I need the Teachers to be updated as well. So in the commented area I need something like this:

 var updatedTeachers=studentEntity.Teachers.ToList();

but of course generic way. I will also have to look inside the DbContext for the teachers DBSet independently. So I will need something like this too:

var exisitingTeachers=MyDbContext.Teachers.ToList();

Any ideas how to do this?

You can call ToList method by passing property value prop.GetValue(entity) in this method:

private IList CollectionToList(object value)
{
    var collectionType = value.GetType().GenericTypeArguments.First();
    var method = typeof(Enumerable).GetMethod("ToList");
    var genericMethod = method.MakeGenericMethod(collectionType);
    return (IList)genericMethod.Invoke(null, new[] { value });
}

In this way you will be able to iterate through collection. If type of property value List or Array and there is no need in creating new collection you can just cast value to IList and iterate through it.

For getting values from database context you can use Set method:

var dbset = MyDbContext.Set(prop.PropertyType.GenericTypeArguments.First());

dbset also could be passed to CollectionToList method, but in that way you will load all table rows from table which could take a lot of time and memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM