Tuesday, August 28, 2012

Oracle ADO.NET EF with transactions


                 ModelContext.Connection.Open();
                 using (var tx = ModelContext.Connection.BeginTransaction())
                 {
                     try
                     {
                         // do stuff...
                         tx.Commit();
                         return true;
                     }
                     catch
                     {
                         tx.Rollback();
                         throw;
                     }
                     finally
                     {
                         if (ModelContext.Connection != null)
                             ModelContext.Connection.Close();
                     }
                 }

Friday, August 17, 2012

How to model a thought/idea (in AI context)?

That is the (ultimate) question for AI...

Derived question: How can we model the thought that gave birth to that (or any) question?

Monday, July 2, 2012

ASP.NET DropDownList does not fire SelectedIndexChanged

Hello,

In one of my working projects - an ASP.NET WebForms, I had a DropDownList control (with AutoPostBack = "true") that was bound to  a ADO.NET EntityFramework entities collection. When the tester tested the webform, the DDL was posting but the default element (which had ID = 0) was selected and the handler for SelectedIndexChanged in the code-behind was not fired.
After some banging my head to my desk for a couple of hours (because other DDLs were working fine), I looked inside the data that was bound to the DDL. And to my surprise, that specific row in the (Oracle) table had the ID = 0, and therefore, no SelectedIndexChanged.

So, check your data too before banging your head to the office desk! :)

Hope it helps someone ... someday...

Thursday, April 26, 2012

ADO.NET EF solution for "The table/view ' does not have a primary key defined. The key has been inferred and the definition was created as a read-only table/view."

Hey there,

In my current project we are using the ADO.NET Entity Framework (for multiple run-time environments: .NET & COM - see previous post for details) and we got the error from the title when generating the entities from database:The table/view '' does not have a primary key defined. The key has been inferred and the definition was created as a read-only table/view.
In order to fix this, you should do this:
- create a non-nullable PK in a table.
- create a virtual non-nullable "PK" and ID in a view.

For Micosoft SQL Server you can use the ROW_NUMBER() function and for Oracle (11g) you can use rownum but that's not enought (I think for MS SQL Server also). You have to add a constraints (yes, views can have constraints):

CREATE OR REPLACE FORCE VIEW "SCHEMA"."VIEW_NAME" ("ID", "COL1", "COL2")
AS
SELECT ROWNUM, COL1, COL2 FROM TABLE
WITH READ ONLY;

alter view VIEW_NAME add constraint id_pk primary key (ID) disable novalidate
;.

 Hope it helps you sometime. :)

Bonus tip: if your view does a UNION (as it was in my case) the second SELECT will have something like SELECT ROWNUM+(SELECT COUNT(*) FROM TABLE1). ;)

Friday, April 13, 2012

[COM] Pass .NET object array to COM

Hey there,
In the life of a .NET developer comes a day when is needed to interact with COM. In this post I will try to explain a way to pass .NET array of objects (can be common CLR objects) to COM environment.
First, you have to expose the .NET object(s) to COM (I will name it Type) by implementing an interface (IType) and decorating them as follows:
[ComVisible(true)]
[System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsDual)]
[Guid("104136e6-af1f-4719-985a-8b65e588e4bb")]
public interface IType



[ComVisible(true)]
[System.Runtime.InteropServices.ClassInterfaceAttribute(System.Runtime.InteropServices.ClassInterfaceType.None)]
[Guid("85aff115-b4ad-473a-9774-285cb1b9ef28")]    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial class Type : IType


Also, you will need some kind of context where all the operations will be hosted. This context, which is a normal C#/.NET class, will also have to be exposed to COM.
Now, lets say you want to pass an IType[] to COM. If you write your method from the context to return an IType[] (public IType[] GetData(string filter)), in the .tlh file (that is generated for C++) the method will have a parameter SAFEARAY**. You could use this but you will have to know the dimension of the array before invoking the GetData(...) method (plus I don't think you will be able to see the COM types in the SAFEARRAY when you'll write your code).

My solution is using the callback idea. I will write the method in the .NET context returning just an IType and using some magic in C++ and C#/.NET I will invoke GetData method multiple times and return the elements one by one. I will also exppose a boolean isFinished parameter as output.
In the .NET code, in order to maintain the state of some variable (like static in C/C++ functions) you can use [ThreadStaticAttribute] or ThreadLocal like this:
internal static class GetMany<T,IT>
        where T : class

        where T : IT
{
     [ThreadStatic]
     private static int counter = 0;

     [ThreadStatic]
     private static IList
<IT> collection;

     public static IT Get(ObjectQuery
<T> query, string predicate, string orderby, out bool isFinished)
     {
         isFinished = true;

         if (collection == null)
         {
             if (!string.IsNullOrEmpty(predicate))
                 query = query.Where(predicate);

             if (!string.IsNullOrEmpty(orderby))
                 query = query.OrderBy(orderby);

             collection = query.Cast
<IT>().ToList();
         }

         if (collection == null || counter >= collection.Count())
         {
             collection = null;
             counter = 0;
             return default(IT);
         }

         isFinished = false;
         return collection[counter++];
     }
}

In the context method GetData I will invoke the method Get from GetMany like this:
GetMany<Type, IType>.Get(collection, predicate, orderby, out isFinished);
In my project case the collection was an ADO.NET EF collection and the predicate and orderby strings were passed from C++.

In .tlh file you will get a function like HRESULT GetData(BSTR predicate, BSTR orderby, VARIANT_BOOL* isFinished, IType* entity); where IType is:
struct __declspec(uuid("104136e6-af1f-4719-985a-8b65e588e4bb"))
IType : IDispatch
.

All we need to do now is to write some code to invoke the GetData method multiple times. For this, since I am using VS2010 with some of the C++ 11 features supported (e.g. auto, lambdas, static_assert, etc), I will write a templated function using a std::function as a callback (just like Func if I may :) ):

template<typename T>
void import(std::vector<T>& container, std::function<HRESULT (VARIANT_BOOL* isFinished, T& result)
> action)
{
    VARIANT_BOOL isFinished = FALSE;

    while (!isFinished)
    {
        T result;
        if (!SUCCEEDED(action(&isFinished, result)))
            throw;

        if (result != nullptr)
            container.push_back(result);
    }
}



When I want to invoke the actual code, I would write:
std::vector<ITypePtr> collection;         
import(collection ,
[&ptr, &predicate, &orderby] (VARIANT_BOOL* isFinished, ITypePtr& result)->
        HRESULT {
            auto hr = testResult.CreateInstance(__uuidof(Type));
            return ptr->GetData(predicate, orderby, isFinished, &result);  

});


After this line, the collection will contain all ITypePtr passed from .NET.

That's all! No more SAFEARRAY**! :)

Thursday, March 15, 2012

MFC Maximize MDI Child

Hey there,
If you want to have a MDI app in MFC and all your MDI Children to be maximized when they are displayed, just override the ActivateFrame function in CChildFrame like this:
void CChildFrame::ActivateFrame(int nCmdShow)
{
    // Create the child frame window maximized
    nCmdShow = SW_MAXIMIZE;

    CMDIChildWnd::ActivateFrame(nCmdShow);
}

Sunday, March 11, 2012

Another issue in Oracle ODBC drivers

Hey
Again something on Oracle. Like my previous post, I am working on a project that has a C++ COM component that connects to an Oracle DB using ODBC drivers.
We decided to port everything to VS2010 and use the Oracle Developer Tools for VS 2010 11.2.0.3. Everything worked great (not everything since VS2010 cannot attach to native code but that's another story) and we were able to generate the EF model using the wizard. When running the app, we noticed that the C++ COM component was not able to connect to Oracle anymore (ORA-12154 error). I tried uninstalling the new driver (using Oracle Universal Installer) but the problem was still there. After setting up the connection to Oracle using the configuration files (we are using ldap.ora and sqlnet.ora, not tsnames.ora) we were able to connect the the database using the new drivers since they messed up the old ones.
Why this happens, I still wait for an answer on Oracle forums... :)

Maybe this helps someone! :)

Wednesday, February 29, 2012

Oracle ODBC issue - AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

In one of the projects I am working on (the application is a hybrid between .NET and COM/C++) the Oracle ODBC driver was used (in the C++ part of the application) - don't ask me why. :)
The client company wanted to migrate the database from Oracle 10g to Oracle 11g and the C++ part was failing with the exception from the title of the post when doing a SELECT * from SomeView where condition.
On the web there are a lot of possible solutions but none of them worked. The strange part is that the exception was only handled in .NET environment - when debugging the C++ part, I've noticed that the GetData  from afxdb.h was failing. So, I enabled tracing in the ODBC Data sources (Control  panel -> Admin tools) and re-execute the app. In this log I was able to see an ORA-01445 error which does not tell much (since the view was not using ROWID). I asked an Oracle DBA what's the error about and he asked me for the view code.
The view code was built using INNER JOINS. So, he told me to remove the INNER JOINS and make a simple SELECT clause: select table1.col1, table2.col2, table3.col2, from table1, table2, table3 where table1.col1 = table2.col1 and table1.col1 = table3.col1. And the application started to do it's job! Strange, right?


Some questions still remain (even if my issue is partially solved):
- why was it working on 10g?
- why this particular view crashed? (there are other views that use inner join and don't cause this)
- why was it working when using the full select (with inner join) and not working when selecting over the view?

Feel free to comment on this issue. ;)

Tuesday, February 21, 2012

0x80040154: Class not registered - ActiveX

When working with Ax control in .NET, keep in mind the target platform of Ax (x86, x6, IA).

Monday, February 20, 2012

LNK2001: unresolved external symbol

I recently joined a C++ project and I had to make the build process with no hard-coded paths to dependencies and I decided to use the References. Everything is good and nice until one of the projects gives the error from the title: linker error - some external symbol could not be found. If you want to get more information on linker, you can use /verbose option.
In my case, at the setting Project Properties->Linker->General->Link Library Dependencies was set to No. Setting it on Yes, fixed all the linker errors.

Hopes it helps!