AWS Lambda使用ODBC连接连接到Redshift DB

时间:2018-02-13 06:21:42

标签: c# lambda odbc aws-lambda amazon-redshift

我正在尝试使用来自.NEt Core 2.0 C#App的AWS Lambda连接到RedShift数据库。

以下是我的方法。

string connString = "Driver={Amazon Redshift (x86)};" +
            String.Format("Server={0};Database={1};" +
            "UID={2};PWD={3};Port={4};SSL=true;Sslmode=Require",
            RedShiftServer, RedShiftDBName, RedShiftUsername,RedShiftPassword, RedShiftPort);
OdbcConnection conn = new OdbcConnection(connString);
conn.Open();

但是在部署到Lambda函数后,我无法连接到RedShift DB(无法打开连接)。

我收到了Bellow Error。

  

需要具有最低版本2.3.1的依赖性unixODBC。       无法加载DLL'libodbc.so.2':指定的模块或其中一个       无法找到依赖项。

看来有些odbc问题,如何解决?

2 个答案:

答案 0 :(得分:0)

在非Windows平台上使用System.Data.Odbc时,必须安装unixODBC(版本2.3.1或更高版本)。然后,您需要安装所需的ODBC驱动程序(在您的情况下,这是Amazon Redshift ODBC驱动程序)并将其注册在odbcinst.ini中。如果是AWS Lambda,则需要检查如何通过部署包来部署unixODBC和Redshift ODBC驱动程序。

答案 1 :(得分:0)

我还尝试使用ODBC从lambda函数的redshift中获取数据,但出现问题“需要最低版本2.3.1的依赖项unixODBC”。

如本线程注释中所述,使用 Npgsql.EntityFrameworkCore.PostgreSQL 库代替使用ODBC。我正在尝试将其组合在一起以提供帮助。这是我的代码,该代码从redshift中读取odbc的连接字符串,并将其与您的模型绑定,该模型的模型和redshift中的表的列名应该相同,而与大小写无关。

 public IEnumerable<T> ExcecuteSelectCommand<T>(string command, string connectionString)
    {
        var relevantConnectionString = GetConnectionStringWithoutDriver(connectionString);
        using (var conn = new NpgsqlConnection(relevantConnectionString))
        {
            try
            {
                conn.Open();
                using (var cmd = new NpgsqlCommand())
                {
                    cmd.Connection = conn;
                    cmd.CommandText = command;
                    var reader = cmd.ExecuteReader();
                    return CreateList<T>(reader);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("There was exception while excecuting the Select Command for Detail, here is exception detail. " + ex.Message, ex);
            }
        }
    }

    private string GetConnectionStringWithoutDriver(string connection)
    {
        return connection.Replace("Driver={Amazon Redshift (x64)}; ", string.Empty);
    }


    private List<T> CreateList<T>(NpgsqlDataReader reader)
    {
        var results = new List<T>();
        Func<NpgsqlDataReader, T> readRow = this.GetReader<T>(reader);

        while (reader.Read())
        {
            try
            {
                var readData = readRow(reader);
                results.Add(readData);

            }
            catch
            {
                throw new Exception("Data mismatch exception has occured");
                //Log the information when data failed to load
            }

        }

        return results;
    }

    private Func<NpgsqlDataReader, T> GetReader<T>(NpgsqlDataReader reader)
    {
        Delegate resDelegate;

        List<string> readerColumns = new List<string>();
        for (int index = 0; index < reader.FieldCount; index++)
        {
            readerColumns.Add(reader.GetName(index));
        }

        // determine the information about the reader
        var readerParam = Expression.Parameter(typeof(NpgsqlDataReader), "reader");
        var readerGetValue = typeof(NpgsqlDataReader).GetMethod("GetValue");

        // create a Constant expression of DBNull.Value to compare values to in reader
        var dbNullValue = typeof(System.DBNull).GetField("Value");
        //var dbNullExp = Expression.Field(Expression.Parameter(typeof(System.DBNull), "System.DBNull"), dbNullValue);
        var dbNullExp = Expression.Field(expression: null, type: typeof(DBNull), fieldName: "Value");
        // loop through the properties and create MemberBinding expressions for each property
        List<MemberBinding> memberBindings = new List<MemberBinding>();
        foreach (var prop in typeof(T).GetProperties())
        {
            // determine the default value of the property
            object defaultValue = null;
            if (prop.PropertyType.IsValueType)
                defaultValue = Activator.CreateInstance(prop.PropertyType);
            else if (prop.PropertyType.Name.ToLower().Equals("string"))
                defaultValue = string.Empty;

            if (readerColumns.Contains(prop.Name.ToLower()))
            {
                // build the Call expression to retrieve the data value from the reader
                var indexExpression = Expression.Constant(reader.GetOrdinal(prop.Name.ToLower()));
                var getValueExp = Expression.Call(readerParam, readerGetValue, new Expression[] { indexExpression });

                // create the conditional expression to make sure the reader value != DBNull.Value
                var testExp = Expression.NotEqual(dbNullExp, getValueExp);
                var ifTrue = Expression.Convert(getValueExp, prop.PropertyType);
                var ifFalse = Expression.Convert(Expression.Constant(defaultValue), prop.PropertyType);

                // create the actual Bind expression to bind the value from the reader to the property value
                MemberInfo mi = typeof(T).GetMember(prop.Name)[0];
                MemberBinding mb = Expression.Bind(mi, Expression.Condition(testExp, ifTrue, ifFalse));
                memberBindings.Add(mb);
            }
        }

        // create a MemberInit expression for the item with the member bindings
        var newItem = Expression.New(typeof(T));
        var memberInit = Expression.MemberInit(newItem, memberBindings);


        var lambda = Expression.Lambda<Func<NpgsqlDataReader, T>>(memberInit, new ParameterExpression[] { readerParam });
        resDelegate = lambda.Compile();

        return (Func<NpgsqlDataReader, T>)resDelegate;
    }