C# 通过 SystemReflection 从实体集中的结果中获取属性

C# get properties from result in entitysets wit SystemReflection

所以我想编写一段代码,从 EntitySet 中获取结果,然后利用 SystemReflection 将数据放入另一个对象中。

例子

对象 Ticket 有一个名为 Application 的 属性,此 属性 的值已在名为 [=14= 的关系 table 中定义].该程序必须检查 TicketRelation 中的 Application 属性,如果存在,它将把数据传递到 TicketApplication 属性 中.

这是我目前拥有的:

private object ConvertRelations(object origin, object to)
{
    // haal relTable op met getValue op relatie property.
    // The propertyInfo types are EntitySets
    List<PropertyInfo> relationProperties = new List<PropertyInfo>();
    PropertyInfo[] cRels = to.GetType().GetProperties();

    foreach (var property in origin.GetType().GetProperties())
    {
        // all the possible endings of relation table names
        if (property.Name.EndsWith("Relatie") || property.Name.EndsWith("Rel") || property.Name.EndsWith("Relaties"))
        {
            relationProperties.Add(property);
        }
    }

    foreach (var relProp in relationProperties)
    {
        var parent = relProp.GetValue(origin, null);
        var parentProps = parent.GetType().GetProperties();
        object match;
        PropertyInfo[] matchProps = null;
        foreach(var parentProp in parentProps)
        {
            // the property's name of which I assumed to hold the data I want was called Item
            if (parentProp.Name == "Item")
            {
                match = parentProp.GetValue(parent, null);
                if(match != null)
                {
                    matchProps = match.GetType().GetProperties();
                }
            }
        }
    }
    // this will return the result later on.
    return null;
}

但不知何故,我尝试在 parentProp 上调用的 GetValue 方法不起作用。我每次都对 GetValue 使用这种方法,但是当我使用 EntitySet 时,它会抛出一个我不明白的异常。 它抛出的堆栈跟踪 parentProp.GetValue(parent, null):

   at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
   at TicketSystemDb.DTO.Helper.DTOHelper.ConvertRelations(Object origin, Object to) in C:\TicketSystem\TicketSystemDb\DTO\Helper\DTOHelper.cs:line 90
   at TicketSystemDb.DTO.Helper.DTOHelper.SimplifyResult(Object from, Object to) in C:\TicketSystem\TicketSystemDb\DTO\Helper\DTOHelper.cs:line 61
   at TicketSystemDb.REPO.TicketREPO.GetTickets() in C:\TicketSystem\TicketSystemDb\REPO\TicketREPO.cs:line 35
   at TicketSystemDb.UOW.TicketUOW.GetTickets() in C:\TicketSystem\TicketSystemDb\UOW\TicketUOW.cs:line 21
   at TicketSystemAPI.Controllers.TicketController.Get() in C:\TicketSystem\TicketSystemAPI\Controllers\TicketController.cs:line 22
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_1.<GetExecutor>b__3(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)

经过一个小时的测试,我终于得到了解决方案。我只是简单地重新设计了数据库,以便每张票只有一个关系 table。这使我可以从关系 table 中获取数据。这里的主要问题是我无法从关系 table 中获得结果,因为存在多个关系,而且如果不使用绑定到特定对象的 LINQ,我将无法访问任何结果。这是更简单的解决方案,但我想让它更具动态性和全球性。

所以考虑到这一点,我只需要 link 票证 table 到相应的关系 table 而不是其他方式。这样做之后,我还对我的代码进行了一些更改,如下所示:

    private object ConvertRelations(object origin, object to)
    {
        List<PropertyInfo> relationProperties = new List<PropertyInfo>();
        PropertyInfo[] cRels = to.GetType().GetProperties();

        foreach (var property in origin.GetType().GetProperties())
        {
            if (property.Name.EndsWith("Relatie") || property.Name.EndsWith("Rel") || property.Name.EndsWith("Relaties"))
            {
                // initial check for class to filter out the auto-generated integer properties
                if(property.PropertyType.IsClass)
                    relationProperties.Add(property);
            }
        }

        // to prevent unnecessary work
        if(relationProperties.Count == 0)
        {
            return null;
        }

        foreach (var relProp in relationProperties)
        {
            var parent = relProp.GetValue(origin, null);
            var parentProps = parent.GetType().GetProperties();
            object match;
            // removed matchProps because the were not needed anymore
            // loop through cRels because of the database redesign
            foreach(var rel in cRels)
            {
                // This code has been changed because the relation property wasn't an EntitySet anymore.
                if (rel.PropertyType.IsClass)
                {
                    // get the link through LINQ instead
                    var link = parentProps.SingleOrDefault(pr => pr.Name == rel.Name);
                    if (link != null)
                    {
                        // this speaks mostly for itself
                        // the simplifyresult is used to convert the match to the DTO model to match the property, which is a DTO
                        match = link.GetValue(parent, null);
                        rel.SetValue(to, SimplifyResult(match, Assembly.GetExecutingAssembly().CreateInstance("TicketSystemDb.DTO."+rel.PropertyType.Name)), null);
                    }
                }
            }
        }
        return to;
    }