Azure功能,实体框架和Oracle DB - 基本POC失败

时间:2018-05-17 12:25:50

标签: visual-studio entity-framework oracle11g azure-functions ef-database-first

我在基本的概念验证工作中遇到了很多麻烦,我通过Azure功能通过实体框架(6.2)访问Oracle DB(11g)。

先决条件: ODT已安装Visual Studio 2017,以及Azure Functions CLI / Core Tools。下面提到的所有内容都完全通过Visual Studio 2017完成,而不是通过Azure门户完成。

取1:

使用Azure Functions模板创建了一个新项目。

已安装的NuGet包EntityFramework(6.2.0),Oracle.ManagedDataAccess(12.2.1100)和Oracle.ManagedDataAccess.EntityFramework(12.2.1100)。注意:使用Azure Functions模板在项目中安装NuGet包时,会在Dependencies - >下添加包。 NuGet,而不是参考文献。

将ADO.NET实体数据模型添加到项目中。

问题:设置我的连接字符串后,选择Entity Framework 6.x不可用,并显示以下错误消息:

  

与最新版本兼容的实体框架数据库提供程序   找不到您的数据的Entity Framework版本   连接。如果您已经安装了兼容的提供商,   确保在执行此操作之前重建了项目。   否则,退出此向导,安装comaptible提供程序,然后   重建您的项目,请执行此操作。

作为最简单的解决方法,我试图继续使用EF5,但是在创建数据库模型时会抛出异常(在选择要包含在模型中的对象之后,包括一些存储过程)。

选2:

按上述方式创建项目并安装了NuGet包。

创建类库项目以促进Oracle交互。

在类库项目中安装了与上面相同的NuGet包。

将ADO.NET实体数据模型添加到类库项目中,并将一些数据库对象添加到数据库模型中。还为特定连接字符串的模型添加了自定义构造函数,因为管理Azure函数中的连接字符串是一个单独的令人头疼的问题,我稍后会处理。

为类库项目添加了一个简单的包装器方法,该方法从数据库模型中调用存储过程:

public static string NameByEmpNo(int empNo)
{
    string result;
    MyEntities entities = new MyEntities("metadata=res://*/MyEntities.csdl|res://*/MyEntities.ssdl|res://*/MyEntities.msl;provider=Oracle.ManagedDataAccess.Client;provider connection string='DATA SOURCE=127.0.0.1:1521/ORCL;PASSWORD=tiger;USER ID=SCOTT'");
    ObjectParameter name = new ObjectParameter("o_empname", typeof(string));
    entities.GET_EMP_NAME_PROC(empNo, name);
    result = (string)name.Value;
    return result;
}

在Azure Functions项目中添加了对类库的引用。

添加了调用NameByEmpNo的函数:

    [FunctionName("GetNameByEmpNo")]
    public static async Task<HttpResponseMessage> GetNameByEmpNo([HttpTrigger(AuthorizationLevel.Function, "get", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
        int empNo = Int32.Parse(req.GetQueryNameValuePairs()
            .FirstOrDefault(q => string.Compare(q.Key, "empno", true) == 0)
            .Value);
        string empName = ScottAccess.NameByEmpNo(empNo);
        return req.CreateResponse(HttpStatusCode.OK, "Employee name: " + empName);
    }

问题:在运行时,调用该函数失败并显示此错误 消息:

  

执行函数时出现异常:GetNameByEmpNo - &gt; ADO.NET   具有不变名称的提供者&#39; Oracle.ManagedDataAccess.Client&#39;是   要么未在机器或应用程序配置文件中注册,要么   无法加载。有关详细信息,请参阅内部异常 - &GT;无法   找到请求的.Net Framework数据提供程序。它可能不是   安装。

奖励信息:通过控制台应用程序调用时,我的类库完美运行。此外,我的Azure Functions应用程序在调用不使用我的类库的函数时非常有效...

我很难过。有没有人有经验让这些技术组合在一起工作,可以提供一些洞察我出错的地方/提供基本连接工作的步骤?

1 个答案:

答案 0 :(得分:2)

Azure Functions中的实体框架将提供程序默认为System.Data.SqlClient,因此SQL连接将在不进行任何配置更改的情况下正常工作,但这意味着您必须对Oracle连接做一些特殊的事情。问题似乎来自Oracle.ManagedDataAccess.Client库假定的配置值在项目的App.Config或Web.Config文件中可用,只要您安装Oracle.ManagedDataAcess.EntityFramework Nuget包,这些配置值就会插入。 Azure Functions没有配置文件,并且我无法在设置json文件中找到任何指定Oracle提供程序的方法。

我在此post

中找到了解决方案

它建议绕过此机制并为Oracle创建一个DbConfiguration,然后使用DbConfigurationType告诉DbContext您正在使用的配置。

public class OracleDbConfiguration : DbConfiguration
{
    public OracleDbConfiguration()
    {
        SetDefaultConnectionFactory(new OracleConnectionFactory());
        SetProviderServices("Oracle.ManagedDataAccess.Client", EFOracleProviderServices.Instance);
        SetProviderFactory("Oracle.ManagedDataAccess.Client", new OracleClientFactory());
    }
}

[DbConfigurationType(typeof(OracleDbConfiguration))]
public partial class MyEntities : IGISContext
{
    //Expose Connection String Constructor
    public MyEntities(string connectionString, int commandTimeoutInSeconds = 30) : base(connectionString)
    {
        this.Database.CommandTimeout = commandTimeoutInSeconds;
    }
}

注意:我使用EF 6 Database First生成了EDMX。 MyEntities是用于提供接受连接字符串的构造函数的局部类。

oracle连接将使用指定的DbConfiguration类,并且任何SQL数据库连接都将使用默认值继续工作。

我的解决方案是使用Nuget软件包:

  • EntityFramework 6.2.0
  • Oracle.ManagedDataAccess 12.2.1100
  • Oracle.ManagedDataAccess.EntityFramework 12.2.1100