In previous blog posts I wrote about using
Devart dotConnect for Oracle as an EntityFramework provider. Once you did this,
you have Devart assemblies linked to your project, why not to use them for
connecting to database with simple ADO.NET too? (if you have such a code too –
I have a lot).
Microsoft has System.Data.OracleClient assembly
to connect to Oracle, but it is discontinued already, it’s great time to
migrate to something else. Devart is a good alternative. Basically you can have
two type of code when using ado.net
- Using ADO.NET directly (coding against classes OracleConnection etc.)
- Using DB agnostic code that is connecting to DB using ADO.NET (coding against abstractions that a data framework is converting to particular Oracle or other DB specific classes). We use Spring Data Access, similar is with Enterprise Library Data Access Application Block and others.
- If you are using ADO.NET directly, you need to change OracleType to OracleDbType and OracleType.DateTime to OracleDbType.Date.
- There are differences in connection strings where Devart has more capabilities for configuration (like specify OracleHome etc. see Devart EF Provider). In connection string you need to change System.Data.OracleClient to Devart.Data.Oracle. Example of connection string is here: <add name="APDataConnection" connectionString="Data Source=*; User ID=*; Password=*;Home=oraclient11g_home1;Persist Security Info=True;Number Mappings = (NUMBER, 0, 38, System.Decimal);" providerName="Devart.Data.Oracle"/>
- OracleClient has different default behavior when calling stored procedures than Devart.Data.Oracle. A Stored procedure can have defaults defined on it’s arguments. It means when this argument is not provided, the default is applied. When calling from OracleClient, you don’t need to provide the arguments that have defaults and it doesn’t matter in which order you pass the arguments to stored procedure (they are passed by default by name). With devart the arguments are by default passed by position not by name. This means you need to pass each argument to every procedure in the same order as the stored procedure expects it and you need to provide the arguments with defaults too from the ado.net code. If you omit the defaulted arguments you get a wrong number of arguments message, which is good. If you change the order of parameters you get totally messy error messages, or just wrong data which are binded to wrong variables. This could really bite. With missing defaults there is no workaround, you need to check all your stored procedures and check if something is missing or not. With the parameter passing order, Devart fortunately has a property on OracleCommand class PassParametersByName which you can set to true and the ordering problem passes away. Devart says, that it’s default setting is because of performance, OracleClient makes queries to database before running the stored procedure to get it’s specification for defaulted arguments, the same is with passing parameters with name, when the server is asked for the stored procedure specification for the argument names.
- Devart has different
data type mappings than oracleClient. OracleClient maps Oracle NUMBER data type
to Decimal .NET type. Devart maps it to different data types depending on the precision
of the NUMBER column (Number(1)-Number(9) to Int32, Number(10-20) to double,
Number without size to Decimal). Again this is better for performance, but if
you have legacy code which expects Decimal everywhere, than this is a problem.
Devart allows you to specify in connection string custom data type mapping
strategy, that solves this issue. <add
name="APDataConnection"
connectionString="Data
Source=*; User ID=*; Password=*;Home=oraclient11g_home1;Persist Security
Info=True;Number Mappings = (NUMBER, 0, 38, System.Decimal);"
providerName="Devart.Data.Oracle"/>
Number Mappings here means that all Number types with size from 0 to 38 will be mapped to Decimal type.Devart data type mappings are here: http://www.devart.com/linqconnect/docs/oracle_datatypemapping.htmlSystem.Data.OracleClient mapping is here:More on Devart connection string configuration possibilities here:http://www.devart.com/dotconnect/oracle/docs/?Devart.Data.Oracle~Devart.Data.Oracle.OracleConnection~ConnectionString.html
- Devart can return the number of affected rows only for INSERT, UPDATE and DELETE DML commands, in all the other cases it returns -1. We used these return values sometimes in our api to indicate whether the operation was successful or not. With these 3 DML commands it is ok. We have several usages of oracle’s MERGE command too, OracleClient can return the correct number of affected rows, devart returns -1. We changed our API where MERGE is used to not count on the return value.
- All the above applies
to using Devart directly with ADO.NET. With Spring Data we run into problem
with the provider itself, it is not a supported provider by default in spring.
Spring has an extension mechanism for providers, where you can register a new
data provider. This is available only in higher versions of Spring.NET (1.3+).
You can define an xml resource file in an assembly where you specify the
provider and than register it in spring configuration. An
example of provider definition is here: Devart Spring Provider Definition . Below
is the registration of the provider:
<spring><context><resource uri="config://spring/objects"/></context><parsers><parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"/></parsers><db:additionalProviders resource="assembly://Aegon.Xing.Modules.Devart/Aegon.Xing.Modules.Devart/DevartSpringDataProviderDefinition.xml"/><objects>
- When using
Spring Data you don’t have access to OracleCommand type where you can set the
PassParametersByName property. In the devart provider definition xml I used a
custom class that derives from OracleCommand class and registering this custom
class instead of Devart OracleCommand class. In this custom class I set the
PassParametersByName property to true. This way every usage of Spring Data with
Devart has this property turned on.
Section from provider registration xml:<!--<constructor-arg name="commandType" value="Devart.Data.Oracle.OracleCommand, Devart.Data.Oracle, Version=8.2.103.0, Culture=neutral, PublicKeyToken=09af7300eec23701"/>--><constructor-arg name="commandType" value="Aegon.Xing.Modules.Devart.OracleCommandWithCustomInit, Aegon.Xing.Modules.Devart"/>The OracleCommandWithCustomInit Class looks like:public class OracleCommandWithCustomInit : OracleCommand{public OracleCommandWithCustomInit() : base(){PassParametersByName = true;}}
And we are
at the end of issues. I had a bunch of integration tests, which were extremely
valuable during the migration. Hope you have too. The migration was 2-3 times
longer than I expected at the end (3 weeks – but doing lot of other things
during these weeks too:)).
At the end
we use Devart for all our data access to oracle (classic ado.net, spring.data,
and entity framework).
Žádné komentáře:
Okomentovat