Consider the following database table (SQL Server 2005). I'd like to use this in EF (v6, .net 4.5.1) with the Translate function but after searching seems this is not supported.
CREATE TABLE Foo
(
pk INT NOT NULL PRIMARY KEY,
Foo VARCHAR(100)
)
Using by-convention mapping that would create a class Foo
with a property Foo
which is not supported by C# syntax. I tried using the ColumnAttribute
:
public partial class Foo
{
[Key]
public virtual int pk {get;set;}
[Column("Foo")]
public virtual string Name {get;set;}
}
This appears to work, but I'd like to make the initial page request load gobs of data via stored procedure and MARS (and use a generic structure so I can reuse it on other pages), so I called the stored procedure and looped through the result sets, calling ObjectContext.Translate
via reflection (similar to the below, but this is abbreviated):
var methTranslate = typeof(ObjectContext).GetMethod("Translate", new[] { typeof(DbDataReader), typeof(string), typeof(MergeOption) });
foreach (var className in classNames)
{
// ...
var translateGenericMethod = methTranslate.MakeGenericMethod(classType);
// ...
reader.NextResult();
var enumerable = (IEnumerable)translateGenericMethod.Invoke(ObjectContext,
new object[] { reader, entitySet.Name, MergeOption.AppendOnly });
}
From multiple things I've read, the ColumnAttribute mapping is not supported. From MSDN:
EF does not take any mapping into account when it creates entities using the Translate method. It will simply match column names in the result set with property names on your classes.
And sure enough, I get and error:
The data reader is incompatible with the specified 'Namespace.Foo'. A member of the type, 'Name', does not have a corresponding column in the data reader with the same name.
The problem is, I do not see any alternative or way to specify/hint at the mapping. I could change the class name but that is less desirable than the property names.
Any workarounds, or any other way to dynamically load data without using Translate
?
A bit tricky, but doable.
The idea is to utilize the
Translate
method by implementing and using a customDbDataReader
that performs the required mapping.Before doing that, let implement a generic
DbDataReader
class that does just delegating to the underlyingDbDataReader
:Nothing fancy - annoyingly overriding all abstract/meaningful virtual members and delegate to the underlying object.
Now the reader that performs name mapping:
Again, nothing fancy. Override a few methods and perform a name to column name and vice versa mapping.
Finally, a helper method that does what you are asking:
ReadSingleResult
is the helper method in question. TheGetPropertyMappings
method is using part of the code from EF6.1 Get Mapping Between Properties and Columns.Sample usage similar to the provided example:
Hope that helps.