Reputation: 10953
I am looking to be able to load an entity by ID using generics and property reflection but am unsure how to accomplish this task using Entity Framework 4.0.
I have a method in my abstract method as such:
public abstract T GetById(object id, TestContext context);
Currently, since it is abstract, I have to implement this method in every single repository class I create as such:
public override TestObject GetById(object id, TestContext context)
{
return context.TestObject.First(x => x.TestId == (int) id);
}
Is there a way to accomplish this same task using reflection and generics in my abstract class?
Upvotes: 3
Views: 3896
Reputation: 6216
I would like to recommend an alternative version to just using GetObjectById as recommended by Bill Daly, the problem is that this method will throw an exception if no object with the given Id exists. This is all fine and dandy if you expect to find your object but otherwise you would probably like to get a null-reference instead. I use the following code that presumes that the model has property with the name Id. I use an extra method to check this in the repository constructor.
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;
}
Upvotes: 0
Reputation: 922
You could adapt this extension method:
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();
}
I have never tried this in any complex scenarios so UAYOR.
Upvotes: 0
Reputation: 36
This is a VB example that I use. My keys are all GUIDs, but you can probably adapt this.
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
Upvotes: 2