C# 实体框架4.0-使用泛型和反射按ID获取

C# 实体框架4.0-使用泛型和反射按ID获取,c#,.net,entity-framework,reflection,C#,.net,Entity Framework,Reflection,我希望能够使用泛型和属性反射按ID加载实体,但不确定如何使用EntityFramework4.0完成此任务 在我的抽象方法中,我有一个方法: public abstract T GetById(object id, TestContext context); 目前,由于它是抽象的,我必须在我创建的每个存储库类中实现此方法: public override TestObject GetById(object id, TestContext context) { return contex

我希望能够使用泛型和属性反射按ID加载实体,但不确定如何使用EntityFramework4.0完成此任务

在我的抽象方法中,我有一个方法:

public abstract T GetById(object id, TestContext context);
目前,由于它是抽象的,我必须在我创建的每个存储库类中实现此方法:

public override TestObject GetById(object id, TestContext context)
{
    return context.TestObject.First(x => x.TestId == (int) id);
}

在我的抽象类中,有没有一种方法可以使用反射和泛型来完成同样的任务?

这是我使用的一个VB示例。我的键都是guid,但您可能可以修改它

Public Shared Function GetKeyPropertyName(ByVal typeName As String) As String
    Dim props = Type.GetType(typeName).GetProperties
    For Each prop In props
        Dim atts = prop.GetCustomAttributes(True)
        For Each att In atts
            If TypeOf (att) Is EdmScalarPropertyAttribute Then
                If DirectCast(att, EdmScalarPropertyAttribute).EntityKeyProperty Then
                    Return prop.Name
                End If
            End If
        Next
    Next
    Throw New ApplicationException(String.Format("No key property found for type '{0}'.", typeName))
End Function

Public Shared Function GetObjectById(Of T As EntityObject)(ByVal id As Guid) As T
    Dim ctx = MyContext
    Dim entityType As Type = GetType(T)
    Dim entityTypeName As String = entityType.ToString
    Dim keyProperty As String = GetKeyPropertyName(entityTypeName)

    Dim container = ctx.MetadataWorkspace.GetEntityContainer(ctx.DefaultContainerName, Metadata.Edm.DataSpace.CSpace)

    Dim entitySetName As String = (From meta In container.BaseEntitySets Where meta.ElementType.FullName = entityTypeName Select meta.Name).First()
    Dim entitySetFullName As String = String.Format("{0}.{1}", container.Name, entitySetName)


    Dim entityKeyValues As IEnumerable(Of KeyValuePair(Of String, Object)) = _
        New KeyValuePair(Of String, Object)() {New KeyValuePair(Of String, Object)(keyProperty, id)}

    Dim key As New EntityKey(entitySetFullName, entityKeyValues)
    Return DirectCast(ctx.GetObjectByKey(key), T)
End Function

您可以调整此扩展方法:

 public static T GetById<T, Y>(this ObjectSet<T> entitySet, Y Id) 
        where T : EntityObject 

    {
        return entitySet.Where(
                e => 
                    e.EntityKey.EntityKeyValues.Select(
                        v => EqualityComparer<Y>.Default.Equals((Y)v.Value, Id)
                    ).Count() > 0)
                .First();            
    }
public static T GetById(此ObjectSet entitySet,Y Id)
其中T:EntityObject
{
返回entitySet.Where(
e=>
e、 EntityKey.EntityKeyValues.Select(
v=>EqualityComparer.Default.Equals((Y)v.Value,Id)
).Count()>0)
.First();
}

我从来没有在任何复杂的场景中尝试过这种方法,所以UAYOR。

我想推荐一种替代版本,而不是像Bill Daly建议的那样只使用GetObjectById。问题是,如果不存在具有给定Id的对象,此方法将引发异常。如果您希望找到您的对象,那么这一切都很好,但是如果您不希望找到空引用,那么您可能希望得到一个空引用。我使用以下代码假定模型具有名为Id的属性。我使用额外的方法在存储库构造函数中检查这一点

public Repository(...)
{
    // code...
    GetByIdAccepted = ExamineIdKey();
}

protected bool ExamineIdKey()
{
    // Fetch the type and look for an "Id"-member
    return typeof(TModel).GetMember("Id", BindingFlags.Instance | BindingFlags.Public).Length > 0;
}

public TModel GetById(object id)
{
    // Validate that GetById is ok for our given model
    if(!GetByIdAccepted)
        throw new InvalidOperationException("error text");

    object model;
    if (Connection.TryGetObjectByKey(new EntityKey(EntityName, "Id", id), out model))
        return (TModel)model;

    return null;
}

这实际上非常接近我所需要的。我主要使用了一些类似于GetKeyPropertyName的东西(进行了一些修改),并且由于我的代码的性质,一旦我有了主键,我就会使用LINQ表达式生成器。