簡體   English   中英

如何按返回類型(例如,通過反射或IL)過濾EF過程?

[英]How do I filter EF procedures by return type (e.g. via reflection or IL)?

假設我們已經通過Entity Framework 6.0從數據庫映射了存儲過程。 我試圖按存儲過程的返回類型過濾存儲過程,然后使用返回類型通過WPF填充網格。

這是涉及的查詢:

AssemblyName assemblyName = new AssemblyName("CT_EntityDataModel");
Assembly asm = Assembly.Load(assemblyName);
var myMethods = new ObservableCollection<MethodInfo>();
// The LINQ below can be offloaded to an ICommand for reflection using the Command pattern. If the Command pattern will be used much, it really should also be a Singleton.
var q = from t in asm.GetTypes()
        where t.IsClass && t.Namespace == "CT_EntityDataModel"
        && t.Name.Equals("CRMEntities")
        select t.GetMethods();

當我使用反射加載存儲過程時,所需的信息在[MethodInfoInstance] .ReturnType.UnderlyingSystemType中。 但是,當我嘗試獲取有關此UnderlyingSystemType的更多信息時,卻很少獲得有用的信息。 這是立即窗口的結果:

j.ReturnType.UnderlyingSystemType
{Name = "ObjectResult`1" FullName = "System.Data.Entity.Core.Objects.ObjectResult`1[[CT_EntityDataModel.PROC_RE_ReadImportInvest_Result, CT_EntityDataModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
    [System.RuntimeType]: {Name = "ObjectResult`1" FullName = "System.Data.Entity.Core.Objects.ObjectResult`1[[CT_EntityDataModel.PROC_RE_ReadImportInvest_Result, CT_EntityDataModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
    base: {Name = "ObjectResult`1" FullName = "System.Data.Entity.Core.Objects.ObjectResult`1[[CT_EntityDataModel.PROC_RE_ReadImportInvest_Result, CT_EntityDataModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
    Assembly: {EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    AssemblyQualifiedName: "System.Data.Entity.Core.Objects.ObjectResult`1[[CT_EntityDataModel.PROC_RE_ReadImportInvest_Result, CT_EntityDataModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    Attributes: Public | BeforeFieldInit
    BaseType: {Name = "ObjectResult" FullName = "System.Data.Entity.Core.Objects.ObjectResult"}
    ContainsGenericParameters: false
    DeclaringMethod: 'j.ReturnType.UnderlyingSystemType.DeclaringMethod' threw an exception of type 'System.InvalidOperationException'
    DeclaringType: null
    FullName: "System.Data.Entity.Core.Objects.ObjectResult`1[[CT_EntityDataModel.PROC_RE_ReadImportInvest_Result, CT_EntityDataModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
    GenericParameterAttributes: 'j.ReturnType.UnderlyingSystemType.GenericParameterAttributes' threw an exception of type 'System.InvalidOperationException'
    GenericParameterPosition: 'j.ReturnType.UnderlyingSystemType.GenericParameterPosition' threw an exception of type 'System.InvalidOperationException'
    GenericTypeArguments: {System.Type[1]}
    GUID: {3cea792c-523d-3659-8584-7b6e3ad1678b}
    HasElementType: false
    IsAbstract: false
    IsAnsiClass: true
    IsArray: false
    IsAutoClass: false
    IsAutoLayout: true
    IsByRef: false
    IsClass: true
    IsCOMObject: false
    IsConstructedGenericType: true
    IsContextful: false
    IsEnum: false
    IsExplicitLayout: false
    IsGenericParameter: false
    IsGenericType: true
    IsGenericTypeDefinition: false
    IsImport: false
    IsInterface: false
    IsLayoutSequential: false
    IsMarshalByRef: false
    IsNested: false
    IsNestedAssembly: false
    IsNestedFamANDAssem: false
    IsNestedFamily: false
    IsNestedFamORAssem: false
    IsNestedPrivate: false
    IsNestedPublic: false
    IsNotPublic: false
    IsPointer: false
    IsPrimitive: false
    IsPublic: true
    IsSealed: false
    IsSecurityCritical: true
    IsSecuritySafeCritical: false
    IsSecurityTransparent: false
    IsSerializable: false
    IsSpecialName: false
    IsUnicodeClass: false
    IsValueType: false
    IsVisible: true
    MemberType: TypeInfo
    Module: {EntityFramework.dll}
    Namespace: "System.Data.Entity.Core.Objects"
    ReflectedType: null
    StructLayoutAttribute: {System.Runtime.InteropServices.StructLayoutAttribute}
    TypeHandle: {System.RuntimeTypeHandle}
    TypeInitializer: null
    UnderlyingSystemType: {Name = "ObjectResult`1" FullName = "System.Data.Entity.Core.Objects.ObjectResult`1[[CT_EntityDataModel.PROC_RE_ReadImportInvest_Result, CT_EntityDataModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}

在UnderlyingSystemType或其他地方是否有方法可以讓我獲取返回類型?

是的,我知道反射的效果是可怕的。 一旦弄清楚如何做到這一點,我將在IL級別優化代碼。 而且,如果您告訴我使用ADO.NET或其他工具,我會告訴您您不知道自己在說什么。 為您提供信息,我能夠直接從數據庫中獲取返回類型的唯一干凈方法是sys.dm_exec_describe_first_result_set_for_object,SQL Server 2012之前的數據庫中未包含該方法。 此外,dm_exec_describe_first_result_set_for_object不能從包含動態SQL的過程中提供很多有用的信息。

在最壞的情況下,我想我可以簡單地使用一個正則表達式從MethodInfo實例.ReturnType.UnderlyingSystemType.FullName中獲取類型,如下所示:

“ System.Data.Entity.Core.Objects.ObjectResult`1 [[CT_EntityDataModel.PROC_RE_ReadImportInvest_Result,CT_EntityDataModel,版本= 1.0.0.0,區域性=中性,PublicKeyToken =空]]”

如果我查看PROC_CT_ReadImportInvest_Result類型,則其定義如下所示:

namespace CT_EntityDataModel
{
    using System;

    public partial class PROC_RE_ReadImportInvest_Result
    {
        public System.DateTime dtDate1 { get; set; }
        public string txtData1 { get; set; }
    }
}

我想要上述FullName值的“ PROC_RE_ReadImportInvest_Result”部分。 有沒有一種更丑陋的方法來獲取此類型,而不是使用正則表達式來提取它?

謝謝德文

[更新(太平洋標准時間2014年4月20日下午5:56):這是解決此問題的最終代碼]:

    // If these values will be consumed by a ViewModel, then we need to use an ObservableDictionary here.
public  Dictionary<MethodInfo, Type> GetTypesDictionary()
{
    // This is for our ViewModel.
    AssemblyName assemblyName = new AssemblyName("CT_EntityDataModel");
    Assembly asm = Assembly.Load(assemblyName);
    // The LINQ below can be offloaded to an ICommand for reflection.
    var q = from t in asm.GetTypes()
            where t.IsClass && t.Namespace == "CT_EntityDataModel"
            && t.Name.Equals("CRMEntities")
            select t.GetMethods();
    // We need to filter these to only those that return a dataset.
    // q can be offloaded to an IPredicateStrategy that returns only the results that match the strategy.
    return (from i in q
            from j in i
            where j.Name.StartsWith("PROC_") && j.Name.Contains("Global")
            let methodType = j.ReturnType.UnderlyingSystemType
            where methodType.IsGenericType
            let test = j.ReturnType.UnderlyingSystemType.GetGenericArguments()
            where test.Length > 0
            select j).ToDictionary(j => j, j => j.ReturnType.UnderlyingSystemType.GetGenericArguments()[0]);
// We can use a Strategy pattern to encapsulate the ".Name.StartsWith" logic.
// This would make an interesting extension method. 
}

看來您正在獲取通用代理對象。 您可以嘗試這樣的事情:

var methodType = [MethodInfoInstance].ReturnType.UnderlyingSystemType;

if(methodType.IsGenericType)
{
    methodType = methodType.GetGenericArguments()[0];
}

PS。 我是從頭開始寫這個的,所以如果有語法錯誤,請原諒。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM