-6

I want to update database object with model object values how do i get the value of the property inside modelObject that is a List?

Imagine an object like this

public class Worker{
     public string Id { get; set; }
     public bool GoodPerson { get; set; }
     public bool Wise { get; set; }
     public List<string> Formation { get; set; }
}

I dont know how to get the values from Formation property, so how can i reflect the edited values in Formation property to my dataBaseObject, CAN YOU PLEASE HELP ME?

how can i reflect these changes using reflection?

public static void UpdateObjectFrom(this object modelObject, object dataBaseObject, string[] excludedProperties = null)
        {

            //WHAT IF THE modelObject is now List<string> ?????, how do i pass the values of modelObject for the dataBaseObject List<string> object


            Type modelObjectType = modelObject.GetType();
            Type dataBaseObjectType = dataBaseObject.GetType();

            PropertyInfo[] modelProperties = modelObjectType.GetProperties();
            PropertyInfo[] dataBaseProperties = dataBaseObjectType.GetProperties();

            if (excludedProperties != null)
            {
                dataBaseProperties = dataBaseProperties.Where(x => !excludedProperties.Contains(x.Name)).ToArray();
            }

            foreach (PropertyInfo dataBasePropInfo in dataBaseProperties)
            {
                if (HasSimpleType(dataBasePropInfo.PropertyType) || dataBasePropInfo.PropertyType.IsGenericType && dataBasePropInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    PropertyInfo modelPropInfo = modelObjectType.GetProperty(dataBasePropInfo.Name);

                    dataBasePropInfo.SetValue(dataBaseObject, modelPropInfo.GetValue(modelObject));
                }
                else if (dataBasePropInfo.PropertyType.IsGenericType)
                {
                    UpdateObjectFrom(dataBasePropInfo.GetValue(dataBaseObject, null), modelObjectType.GetProperty(dataBasePropInfo.Name).GetValue(modelObject, null));
                }
                else if (dataBasePropInfo.PropertyType.IsClass && !dataBasePropInfo.PropertyType.FullName.StartsWith("System."))
                {
                    UpdateObjectFrom(dataBasePropInfo.GetValue(dataBaseObject, null), modelObjectType.GetProperty(dataBasePropInfo.Name).GetValue(modelObject, null));
                }
            }
        }

        private static bool HasSimpleType(Type tipo)
        {
            return tipo.IsPrimitive || tipo == typeof(string) || tipo.IsEnum || tipo == typeof(Decimal) || tipo == typeof(DateTime);
        }
Raphael Ribeiro
  • 529
  • 5
  • 18
  • 6
    Why do you need to use reflection? This really appears to be an [XY Problem](http://meta.stackexchange.com/a/66378). – Erik Philips Jul 24 '14 at 16:51
  • I am curious to know why you want to use reflection?Reflection has got its own side effect? – Rangesh Jul 24 '14 at 16:52
  • 1
    What have you tried? What problems are you having? What about what you're doing need to be dynamic that is preventing you from doing this without reflection? – Servy Jul 24 '14 at 16:52
  • 4
    Indeed - if you *know* you've got a `List`, you don't need to use reflection. If you *don't* know you've got a `List`, what *do* you know? – Jon Skeet Jul 24 '14 at 16:52
  • Help point you in the right direction: http://stackoverflow.com/questions/1347936/indentifying-a-custom-indexer-using-reflection-in-c-sharp – TyCobb Jul 24 '14 at 16:53
  • i am creating something greater, but i need to learn how to do this before. =] – Raphael Ribeiro Jul 24 '14 at 16:53
  • @RaphaelRibeiro How are you going to learn if you're just asking other people to do it for you? You'll actually learn how to do this if you actually do it yourself. – Servy Jul 24 '14 at 16:54
  • i dont know if it is a List, but i want to know how to do it for string or int, but not if the elements are class type – Raphael Ribeiro Jul 24 '14 at 16:56
  • `Console.WriteLine(x.ToString())` – CamperWill Jul 24 '14 at 17:03
  • @RaphaelRibeiro That said, experienced .Net developers are going to immediately see that reflection is not needed as the question is stated. Instead you should change the question to List. Also, you probably want to be more explicit about what you want to do with T. If it is simply write to the console. Then my earlier comment Console.WriteLine(x.ToString()) will work without reflection. – CamperWill Jul 24 '14 at 18:49

1 Answers1

0

Before you read any further I suggest you check out AutoMapper. AutoMapper is designed to map data from one type to another. From what I see, this is what you are trying to accomplish.

One note of caution, AutoMapper does not perform a deep copy on lists. So if you modify the list on the source object, it will affect the list on the destination object.

A shallow copy is straight forward, just copy the list directly, the same as you are with your primitive and nullable types.

Something else to consider with your code. You are checking the property names, but not the types of the two objects. What if you have int Id on one class with string Id on the other?

If you must have a deep copy of the list, it gets a little more complex. But here is what I came up with (note: this is not a true deep copy, because the members of the list are not cloned):

else if (dataBasePropInfo.PropertyType.IsGenericType)
{
    var args = dataBasePropInfo.PropertyType.GetGenericArguments();
    var lstType = typeof (List<>).MakeGenericType(args);
    if (lstType.IsAssignableFrom(dataBasePropInfo.PropertyType))
    {
        PropertyInfo modelPropInfo = modelObjectType.GetProperty(dataBasePropInfo.Name);
        var target = Activator.CreateInstance(lstType);
        var source = modelPropInfo.GetValue(modelObject);
        lstType.InvokeMember("AddRange", BindingFlags.InvokeMethod, null, target, new[] {source});

        dataBasePropInfo.SetValue(dataBaseObject, target);
    }
    else
    {
        UpdateObjectFrom(dataBasePropInfo.GetValue(dataBaseObject, null), modelObjectType.GetProperty(dataBasePropInfo.Name).GetValue(modelObject, null));
    }
}

Recommended reading: How to: Examine and Instantiate Generic Types with Reflection

Another option

You could use a combination of reflection and serialization.

  1. Serialize your source object to a stream
  2. Deserialize a new copy of your source object (the new object will not share any of the references of the original source)
  3. Copy properties from source-clone to target using: dataBasePropInfo.SetValue(dataBaseObject, modelPropInfo.GetValue(modelObject));
CamperWill
  • 108
  • 7
  • Actually i dont have to copy, i just need to transfer/change the value of database object, your answer showed me the way. Thanks for the link you said about to Examine types, it's really important. thanks. – Raphael Ribeiro Jul 25 '14 at 14:05