Sunday, January 19, 2014

Entity Framework 6 + Stored Procedure = The type or namespace name 'Objects' does not exist in the namespace 'System.Data'

(this post is formatted poorly, it will be fixed later because I really need to post this one before I forget it)

On my latest project I upgraded to Entity Framework Version 6 and everything was fine until I tried to add a Stored Procedure function import.

After adding that I could no longer build the project and the error message of "The type or namespace name 'Objects' does not exist in the namespace 'System.Data' (are you missing an assembly reference?)" started showing up.

I found the solution here and the fix is to download the Entity Framework 6 Tools for Visual Studio 2012/2013.

Note:  After you install the tools, your model will still not compile.  To fix it you must either:

  • Delete and re-add the Model.edmx to your project
OR
  • Create another model and copy the Context.tt file from it over your initial model.  After you copy the .tt, on Line 5 you'll need to set the name of your original Model.edmx
Line 5: const string inputFile = @"OriginalModel.edmx";
Now, after it compiled I ran into the fun error message "System.InvalidOperationException: The value of EntityCommand.CommandText is not valid for a StoredProcedure command. The EntityCommand.CommandText value must be of the form 'ContainerName.FunctionImportName'."  At this point I was almost ready to write EF6 off as unusable, but I found a page at http://www.dotnetbits.com/entity-framework-6-t4-templates/ that gave me the updates to Context.tt that I needed.

Look for the method signature

public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption)

Replace that method with

public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption)
{
var parameters = _typeMapper.GetParameters(edmFunction);
var returnType = _typeMapper.GetReturnType(edmFunction);
var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()));
if (includeMergeOption)
{
callParams = ", mergeOption" + callParams;
}
return string.Format(
CultureInfo.InvariantCulture,
"return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});",
returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">",
edmFunction.FullName,
callParams);
}