Question

.. Hi, i'm trying to concatenate some column values from any entity like this:

var valor = "";

        PropertyDescriptorCollection objProperties = TypeDescriptor.GetProperties(obj);


        foreach (PropertyDescriptor objProperty in objProperties)
        {

            if (objProperty.Name != "AuditoriaUC" && objProperty.Name != "AuditoriaFC"
                && objProperty.Name != "AuditoriaIPC" && objProperty.Name != "AuditoriaUM"
                && objProperty.Name != "AuditoriaFM" && objProperty.Name != "AuditoriaIPM"
                && objProperty.Name != "AuditoriaEliminado")
            {
                valor = valor + " " + objProperty.Name + ": " + Convert.ToString(objProperty.GetValue(obj));
            }
        }

        return valor;

However, it also shows me the column references. In other words, it also prints this at the end:

"ArchivosAdjuntos:System.Data.Objects.DataClasses.EntityCollection`1[XXX.MyProject.Model.Entities.ArchivosAdjuntos] 
 CorrelativoActualPorPeriodo: XXX.MyProject.Model.Entities.CorrelativoActualPorPeriodo
 CorrelativoActualPorPeriodoReference: System.Data.Objects.DataClasses.EntityReference`1[XXX.MyProject.Model.Entities.CorrelativoActualPorPeriodo] 
 EntityState: Modified 
 EntityKey: System.Data.EntityKey"

I Would only like to return the column values, which I can achieve by just comparing the last column value with a hardcoded string to break the foreach. But I would really want to know if there is a better way.

Was it helpful?

Solution

First you could use the GetProperties method of the Type class, which allows some filtering like returning only public properties:

PropertyInfo[] props = obj.GetType().GetProperties(BindingFlags.Public 
                                                   | BindingFlags.Instance);

Then you could use LINQ for filtering the reference type properties.For example you could remove all reference type properties (except strings) and iterate over them:

var valueProps = props.Where(p => !p.PropertyType.IsClass 
                                || p.PropertyType == typeof(string))
valueProps.ToList().ForEach(p => 
                           valor += p.Name + ": " 
                                 + (p.GetValue(obj) ?? "null"));

Finally, for those properties that you are excluding using a hardcoded list, you could add that hardcoded list of property names into the filtering expression above. However you could also consider adding an attribute on the fields that you want to exclude and remove any property including that attribute from the properties list. This would be the attribute

[AttributeUsage(AttributeTargets.Property)]
public class ExcludeThisPropertyAttribute: Attribute
{
}

You could set it on you classes like

public class YourClass
{
    public string PropertyThatIsIncluded { get; set; }
    public int ThisIsIncludedToo { get; set; }
    //more value type properties to be included ...

    [ExcludeThisProperty]
    public string AuditoriaUC { get; set; }
    [ExcludeThisProperty]
    public string AuditoriaFC { get; set; }
    //more value type properties explicitly excluded ...

    //reference type properties like this one will be automatically excluded
    public CorrelativoActualPorPeriodo CorrelativoActualPorPeriodo { get; set; }
}

Then the expression to extract the value type attributes would be updated to exclude those that contain the attribute:

var valueProps = props.Where(p => 
               p.GetCustomAttributes(typeof(ExcludeThisPropertyAttribute), true) == 0
               &&(!p.PropertyType.IsClass 
                    || p.PropertyType == typeof(string)))    

In your case it seems you are using entity framework, so if your classes have been generated by EF, in order to be able to set attributes on properties you would need to follow an approach like using an auxiliary metadata class

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top