views:

74

answers:

1

Hello guys,

I have a database (which I can not modify) with 6 tables in Oracle 11g. All tables have a OID artificial column for ID, and its type is RAW(16). The DBA answered me that they are in raw and not in integer because this way the IDs will be unique in all six tables - and we must guarantee that.

I'm developing the UI in C# and for data layer I'm (trying) to use NHibernate. How can I implement the ID generator in a way that attends this necessities?

Thanks very much,

Pedro Dusso

My map is:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="MetaManager.Data.Job,MetaManager.Data" table="JOB" lazy="true">
    <id name="Oid" column="OID" type="Guid">
      <generator class="guid.comb" />
    </id>
    <property name="JobId" type="Decimal">
      <column name="JOB_ID" length="10" sql-type="number" not-null="true" />
    </property>
    <bag name="EtlProcesses" inverse="true" cascade="all-delete-orphan">
     <key column="JOB_ID"/>
      <one-to-many class="MetaManager.Data.EtlProcess,MetaManager.Data"/>
    </bag>
  </class>
</hibernate-mapping>

And my class code is:

namespace MetaManager.Data
{
    public class Job
    {
        public virtual Guid Oid { get; set; }
        public virtual decimal JobId { get; set; }
        private IList<EtlProcess> _EtlProcesses;
        public virtual IList<EtlProcess> EtlProcesses
        {
            get
            {
                if (_EtlProcesses == null)
                    _EtlProcesses = new List<EtlProcess>();
                return _EtlProcesses;
            }
            set
            {
                _EtlProcesses = value;
            }
        }
    }
}

I'm creating a Job object and them trying to save it in the database. The catch of try

Job job = new Job(1, "Test Job", DateTime.Now, DateTime.MaxValue, "A", "Dusso");

Guid retVal;
ITransaction transaction = null;
try
{
    transaction = Session.BeginTransaction();
    Session.SaveOrUpdate(job);

    if (transaction != null && transaction.IsActive)
       transaction.Commit(); //the exception is trow here!
    else
       Session.Flush();
       retVal = job.Oid;
}
catch(Exception ex)
{...}

The complete exception is:

{System.InvalidCastException: Failed to convert parameter value from a Guid to a Byte[]. ---> System.InvalidCastException: Object must implement IConvertible. at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) at System.Data.OracleClient.OracleParameter.CoerceValue(Object value, MetaType destinationType) --- End of inner exception stack trace --- at System.Data.OracleClient.OracleParameter.CoerceValue(Object value, MetaType destinationType) at System.Data.OracleClient.OracleParameter.SetCoercedValueInternal(Object value, MetaType metaType) at System.Data.OracleClient.OracleParameterBinding.PrepareForBind(OracleConnection connection, Int32& offset) at System.Data.OracleClient.OracleCommand.Execute(OciStatementHandle statementHandle, CommandBehavior behavior, Boolean needRowid, OciRowidDescriptor& rowidDescriptor, ArrayList& resultParameterOrdinals) at System.Data.OracleClient.OracleCommand.ExecuteNonQueryInternal(Boolean needRowid, OciRowidDescriptor& rowidDescriptor) at System.Data.OracleClient.OracleCommand.ExecuteNonQuery() at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) at NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation) at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session) at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Object obj, ISessionImplementor session) at NHibernate.Action.EntityInsertAction.Execute() at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) at NHibernate.Engine.ActionQueue.ExecuteActions(IList list) at NHibernate.Engine.ActionQueue.ExecuteActions() at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) at NHibernate.Impl.SessionImpl.Flush() at NHibernate.Transaction.AdoTransaction.Commit() at MetaManager.Data.Services.JobDataControl.Save(Job job) in C:\Users\Pedro_Dusso\documents\visual studio 2010\Projects\MetaManager\MetaManager.Data\Services\JobDataControl.cs:line 45}

And sincerely I don't understand your first suspicious. In the database, I have a JOB table and a ETL_PROCESS table. Their relationship is like 1:n, a JOB can have many etl processes.

PS.: I'm adding my nhibernate configuration, maybe it help.

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="dialect">NHibernate.Dialect.Oracle9Dialect</property>
      <property name="connection.driver_class">NHibernate.Driver.OracleClientDriver</property>
      <property name="connection.connection_string_name">MetaManager</property>
      <mapping assembly="MetaManager.Data"/>
    </session-factory>
  </hibernate-configuration>

Error using the ODP: {NHibernate.HibernateException: Could not create the driver from NHibernate.Driver.OracleDataClientDriver. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> NHibernate.HibernateException: The IDbCommand and IDbConnection implementation in the assembly Oracle.DataAccess could not be found. Ensure that the assembly Oracle.DataAccess is located in the application directory or in the Global Assembly Cache. If the assembly is in the GAC, use element in the application configuration file to specify the full name of the assembly. at NHibernate.Driver.ReflectionBasedDriver..ctor(String driverAssemblyName, String connectionTypeName, String commandTypeName) at NHibernate.Driver.OracleDataClientDriver..ctor() --- End of inner exception stack trace --- at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.Activator.CreateInstance(Type type) at NHibernate.Connection.ConnectionProvider.ConfigureDriver(IDictionary2 settings) --- End of inner exception stack trace --- at NHibernate.Connection.ConnectionProvider.ConfigureDriver(IDictionary2 settings) at NHibernate.Connection.ConnectionProvider.Configure(IDictionary2 settings) at NHibernate.Connection.ConnectionProviderFactory.NewConnectionProvider(IDictionary2 settings) at NHibernate.Cfg.SettingsFactory.BuildSettings(IDictionary`2 properties) at NHibernate.Cfg.Configuration.BuildSettings() at NHibernate.Cfg.Configuration.BuildSessionFactory() at MetaManager.Data.SessionProvider.get_Session() in C:\Users\Pedro_Dusso\documents\visual studio 2010\Projects\MetaManager\MetaManager.Data\SessionProvider.cs:line 27 at MetaManager.Data.AttributeDataService.get_Session() in C:\Users\Pedro_Dusso\documents\visual studio 2010\Projects\MetaManager\MetaManager.Data\Services\AttributeDataService.cs:line 33 at MetaManager.Data.AttributeDataService.Save(Attribute attribute) in C:\Users\Pedro_Dusso\documents\visual studio 2010\Projects\MetaManager\MetaManager.Data\Services\AttributeDataService.cs:line 58 at Debug.Program.Main(String[] args) in C:\Users\Pedro_Dusso\documents\visual studio 2010\Projects\MetaManager\Debug\Program.cs:line 24 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()}

Thanks again,

+1  A: 

RAW is a binary type in Oracle, which maps very well to a unique identifier (16 bytes == 128 bits)

So, define your Id property as Guid and use guid.comb as the generator.

Diego Mijelshon
I will try that!
Pmdusso
Finally (after some effort to configure it correctly..) I got NHibernate working. But I get this exception: "Failed to convert parameter value from a Guid to a Byte[]". Isn't supposed to GUID and byte[] work fine together? Thanks again!
Pmdusso
You are doing something weird with the types. Can you post your mapping? You shouldn't have any reference to byte[]
Diego Mijelshon
For sure! I added the code in the original topic. Thanks very much for the help your are providing!
Pmdusso
First suspicious thing: EtlProcesses seems to be mapping the key to a field that is not the PK. Also, when do you get that error? can you post the full exception?
Diego Mijelshon
I re-edited the question Diego. I'm investigating here also... Thanks in advance
Pmdusso
Have you tried using ODP instead of System.Data.OracleClient?
Diego Mijelshon
IF by ODP you mean the NHibernate.Driver.OracleDataClientDriver, I'm getting the fallowing error (after referenced the Oracle.DataAccess dll in my MetaManager.Data project) [edited]:
Pmdusso
You have to install ODP.NET (from Oracle) before using that.
Diego Mijelshon
I found a folder here C:\Oracle\product\11.1.0\client_1\ODP.NET\bin\2.x. But I supposed that my Oracle.DataAccess dll version should be 4.x or great, am I right? Using this dll the 'problem persists' :(
Pmdusso
Well... I'm downloading the latest version in Oracle website itself. Maybe this will work!! Lets see! Thanks man! Hope to bring good news soon.
Pmdusso