EFOracleProvider 示例使用的方法 Entity Framework Provider for Oracle 資料收集
2009-04-21 20:50
856 查看
EFOracleProvider 示例使用的方法 Entity Framework Provider for Oracle 資料收集
MS 的示例
http://code.msdn.microsoft.com/EFOracleProvider/Release/ProjectReleases.aspx?ReleaseId=1395
示例:http://blog.ardekantur.com/2008/08/my-adventures-with-entity-framework-and-oracle/
網上找的例子說明
because that’s the only way it can follow what I actually managed to
accomplish.
I’ve been obsessed with learning LINQ
to SQL since I first heard of it, but never really had the time. Besides
time constraints, I was also put off by the fact that there seemed to be nothing
coming from
the Oracle camp regarding the exciting new technology I saw unfolding. After
a while I began hearing whispers of the Entity
Framework, a complete object-relational mapping solution coming from the
Microsoft camp, and was immediately interested. I had never really taken a look
at the other available ORM solutions for .NET, NHibernate and the like, simply
because I thought there would be a slim chance I would be able to use both
Oracle and LINQ with them without too much trouble. As it stands, I had exactly
that trouble with Entity Framework, but it feels justified in a weird way. I’m
sure after this I’ll try taking a look around for other available solutions, but
so far this looks extremely promising, if a little unpolished.
This all starts off with EFOracleProvider, an
Entity Framework-friendly provider used to generate the necessary classes and
mapping files for database access. Compiling
me a DLL and some configuration settings I could toss at the already existing
data model generator, EdmGen.exe, to
generate the classes that map to the database tables and fields I specified.
I’m going to show you the files I worked with in all of this, but I’m not
going to obfuscate them, or simplify them. I’m going to give you an idea of the
exact situation I was in, in order to show you the problems I encountered, and
how easy it is to encounter them. I’d also like to remind you that use of
it is extremely rough quality code. This was more of an adventure than a focused
goal, but it raises a lot of questions.
storage model for the part of the database I wanted to present to .NET. I
decided to go straight to our live database and take my queues from it. I took a
small cross-section of our available schema — just a single table, with two
columns, both
Yes,
numbers. But it’s also our primary key, so it’ll make do. In any event.
The storage model file is XML, and fairly easy to create, but has a lot of
hidden gotchas that we’ll cover.
Fairly straightforward. We’re reminded in the
documentation to set the
version number of our database. You’ll note that your namespace seems to require
a secondary class. You cannot place your entities in
specified the table name in the
map cleanly to what .NET expects.
Fire up
the object model, and configuring your application for use with
enough — take the two
and throw them into a project, and reference that project in your app.
I had initially put all of the test and generation files in one root
directory on my disk, just to keep track of them. This turned out to be a good
idea for a secondary reason. In your application configuration, you must provide
access to the metadata files you’ve just created. The example code in the
Note those
to resource files, but I didn’t see any of the projects involved actually
containing one. On top of that, there’s that double-namespace thing, i.e.
to even work a little bit with my configuration, so I just pointed my
application at the root directory I created, that contained all of the necessary
files. I imagine on a test or application server, leaving these files in a
common place may be the most useful option.
Don’t forget to add
Also note that I didn’t use the
the test code was listed as
the provider in the connection string is our good old
Finally, write a small piece of code to test the functionality.
Whoops. What did we do wrong? Well, let’s look at the SQL that was
generated.
What’s wrong with that? Actually, something very subtle and dangerous that
I’m sure is causing Oracle a lot of pain in trying to get a provider out for the
Entity Framework. Observer the following session in SQL*Plus:
This hearkens back to a long-standing conflict in dealing with Oracle and
mixed-case or reserved identifier names, to wit: In order to ensure that table
names that happen to be reserved keywords can be used, we need to enclose them
in double-quotes. But we can create tables with or without quotes, with
differing cases, and create two different tables. We may not be able to rely on
the user telling us the exactly correct name of a table in our storage model
file, but we can’t convert it to all caps without the risk of accidentally
referring to a different table!
My solution at this point was to cave and refer to the table name in all caps
in my storage model file. But now the problem is the column names! And we can’t
refer to a column name in the storage model, but we can in the mapping file, the
column names to all caps, and have it compile. What I ended up doing was simply
referring to all of the fields in all caps in the storage model, which of course
breaks our code, making us refer to
uglifying the constructor code for creating new objects:
the idea that we can specify a table name in our storage model file, but not
column names. This seems entirely too half-baked to me, but maybe I just don’t
understand the conceptual tactics behind a move like that.
And I just noticed this as I was signing off, a quick bizarre thing I wanted
to try:
Take the top ten items that have an uppercase A in them. Simple enough,
right? Nope. A rewriting of the generated SQL:
This is a mess. First off, that
what we expect, no matter what the rest of the query is. Secondly,
Little things like this are going to be the hell Oracle would have to go through
to get a decent provider out there for Entity Framework, and I don’t even envy
them a little bit.
One more thing I want to say about all of this. The work I did above took
seven hours, a lot of Googling, a lot of searching through documentation, and a
lot of guessing. The following is how everything above would be handled in my current favorite Ruby ORM.
This is not to compare languages or ideologies, but methodologies. Simplicity
always trumps complexity in the software engineering world. Always always
always. Make Entity Framework easier for people to use, and it could be a
godsend for shops that want a Microsoft-written ORM solution.
I’ll try and answer any questions anyone has, but this is literally the
maximum scope of what I was able to accomplish. I’ll probably throw myself back
at it later this weekend.
This entry was written by Ardekantur, posted on
August 8, 2008 at 11:07
am, filed under Concepts, Configuration Files, Experiments, Software Design, Tutorials and tagged .net, eforacleprovider, entity
framework, oracle. Bookmark the permalink. Follow any comments here with the RSS feed for this post. Post a comment or
leave a trackback: Trackback URL.
MS 的示例
http://code.msdn.microsoft.com/EFOracleProvider/Release/ProjectReleases.aspx?ReleaseId=1395
示例:http://blog.ardekantur.com/2008/08/my-adventures-with-entity-framework-and-oracle/
網上找的例子說明
My Adventures with Entity Framework and Oracle
Brief Overview
Okay, so here we go. This is going to be a bit of a rambling adventure,because that’s the only way it can follow what I actually managed to
accomplish.
I’ve been obsessed with learning LINQ
to SQL since I first heard of it, but never really had the time. Besides
time constraints, I was also put off by the fact that there seemed to be nothing
coming from
the Oracle camp regarding the exciting new technology I saw unfolding. After
a while I began hearing whispers of the Entity
Framework, a complete object-relational mapping solution coming from the
Microsoft camp, and was immediately interested. I had never really taken a look
at the other available ORM solutions for .NET, NHibernate and the like, simply
because I thought there would be a slim chance I would be able to use both
Oracle and LINQ with them without too much trouble. As it stands, I had exactly
that trouble with Entity Framework, but it feels justified in a weird way. I’m
sure after this I’ll try taking a look around for other available solutions, but
so far this looks extremely promising, if a little unpolished.
This all starts off with EFOracleProvider, an
Entity Framework-friendly provider used to generate the necessary classes and
mapping files for database access. Compiling
EFOracleProvidergave
me a DLL and some configuration settings I could toss at the already existing
data model generator, EdmGen.exe, to
generate the classes that map to the database tables and fields I specified.
I’m going to show you the files I worked with in all of this, but I’m not
going to obfuscate them, or simplify them. I’m going to give you an idea of the
exact situation I was in, in order to show you the problems I encountered, and
how easy it is to encounter them. I’d also like to remind you that use of
EFOracleProvideris not recommended in production environments, as
it is extremely rough quality code. This was more of an adventure than a focused
goal, but it raises a lot of questions.
Observing the Database
My first step, after compilingEFOracleProvider, was to create a
storage model for the part of the database I wanted to present to .NET. I
decided to go straight to our live database and take my queues from it. I took a
small cross-section of our available schema — just a single table, with two
columns, both
VARCHAR2s.
+--------------------------+ | tblAsset | +--------------------------+ | Asset_Number | | Asset_Type | +--------------------------+
Yes,
Asset_Numberis a string. It refers to alphanumeric serial
numbers. But it’s also our primary key, so it’ll make do. In any event.
The storage model file is XML, and fairly easy to create, but has a lot of
hidden gotchas that we’ll cover.
<?xml version="1.0" encoding="utf-8"?> <Schema Namespace="TestAppEFModel.Administration" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl" Provider="EFOracleProvider" ProviderManifestToken="10g"> <EntityContainer Name="dbo"> <EntitySet Name="Assets" EntityType="TestAppEFModel.Administration.Assets" Table="tblAsset" /> </EntityContainer> <EntityType Name="Assets"> <Key> <PropertyRef Name="Asset_Number" /> </Key> <Property Name="Asset_Number" Type="varchar2" Nullable="false" StoreGeneratedPattern="Identity" /> <Property Name="Asset_Type" Type="varchar2" MaxLength="50" /> </EntityType> </Schema>
Fairly straightforward. We’re reminded in the
EFOracleProvider
documentation to set the
ProvierManifestTokento the relevant
version number of our database. You’ll note that your namespace seems to require
a secondary class. You cannot place your entities in
TestAppEFModel, you need to create something like
TestAppEFModel.Administration. Also note that I’ve manually
specified the table name in the
EntitySettag, since it does not
map cleanly to what .NET expects.
Fire up
EdmGen.exe:
C:/OracleEFTests>edmgen.exe /mode:FromSSDLGeneration / /c:"Data Source=TNSNAME;User ID=user_id;Password=password..." / /project:TestApp /prov:EFOracleProvider / /inssdl:TestAppEFModel.Oracle.ssdl /project:TestAppEFModel Microsoft (R) EdmGen version 3.5.0.0 Copyright (C) Microsoft Corporation 2007. All rights reserved.
Creating conceptual layer from storage layer... Writing msl file... Writing csdl file... Writing object layer file... Writing views file... Generation Complete -- 0 errors, 0 warnings
Preparing the Application
There are two basic steps to preparing your application: Providing a DLL ofthe object model, and configuring your application for use with
EFOracleProviderand your database. Providing the DLL is easy
enough — take the two
.csfiles created by
EdmGen.exe
and throw them into a project, and reference that project in your app.
I had initially put all of the test and generation files in one root
directory on my disk, just to keep track of them. This turned out to be a good
idea for a secondary reason. In your application configuration, you must provide
access to the metadata files you’ve just created. The example code in the
EFOracleProviderproject used the following syntax in its
App.config:
<add name="NorthwindEntities" connectionString="provider=EFOracleProvider;metadata=res://NorthwindEFModel/NorthwindEFModel.NorthwindEFModel.csdl|res://NorthwindEFModel/NorthwindEFModel.NorthwindEFModel.msl|res://NorthwindEFModel/NorthwindEFModel.NorthwindEFModel.ssdl;Provider Connection String='data source=XE;user id=edmuser;password=123456'" providerName="System.Data.EntityClient" />
Note those
res://addresses. I imagine those are used to refer
to resource files, but I didn’t see any of the projects involved actually
containing one. On top of that, there’s that double-namespace thing, i.e.
NorthwindEFModel.NorthwindEFModel.csdl. I couldn’t get this syntax
to even work a little bit with my configuration, so I just pointed my
application at the root directory I created, that contained all of the necessary
files. I imagine on a test or application server, leaving these files in a
common place may be the most useful option.
<add name="TestServer" connectionString="provider=EFOracleProvider;metadata=C:/OracleEFTests/TestAppEFModel.csdl|C:/OracleEFTests/TestAppEFModel.msl|C:/OracleEFTests/TestAppEFModel.Oracle.ssdl;Provider Connection String='Data Source=TNSNAME;User ID=user_id;Password=password...'" />
Don’t forget to add
EFOracleProviderto the
<DbProviderFactories>section of your configuration, as well.
Also note that I didn’t use the
providerNameattribute, which in
the test code was listed as
System.Data.EntityClient, even though
the provider in the connection string is our good old
EFOracleProvider.
Finally, write a small piece of code to test the functionality.
using System; using System.Collections.Generic; using System.Data.EntityClient; using System.Linq; using System.Configuration; using System.Text; using TestAppEFModel; namespace TestAppEFOracleTests { class Program { public static void Main() { TestAppEFModelContext context = new TestAppEFModelContext( ConfigurationManager.ConnectionStrings["TestServer"].ConnectionString ); var query = from asset in context.Assets where asset.Asset_Type == "TEST ASSET TYPE" select asset; foreach(var asset in query) Console.WriteLine("{0}, {1}", asset.Asset_Number, asset.Asset_Type); } } }
The Troubles
And we’re good to go, right? Not quite.ORA-00942: table or view does not exist
Whoops. What did we do wrong? Well, let’s look at the SQL that was
generated.
SELECT "Extent1"."Asset_Number", "Extent1"."Asset_Type" FROM "tblAsset" "Extent1" WHERE (N'TEST ASSET TYPE' = "Extent1"."Asset_Type")
What’s wrong with that? Actually, something very subtle and dangerous that
I’m sure is causing Oracle a lot of pain in trying to get a provider out for the
Entity Framework. Observer the following session in SQL*Plus:
SQL> DESC tblAsset; Name Null? Type -------------- -------- -------------- ASSET_NUMBER NOT NULL VARCHAR2(50) ASSET_TYPE VARCHAR2(50) SQL> DESC "tblAsset"; ERROR: ORA-04043: object "tblAsset" does not exist SQL> DESC "TBLASSET"; Name Null? Type -------------- -------- -------------- ASSET_NUMBER NOT NULL VARCHAR2(50) ASSET_TYPE VARCHAR2(50)
This hearkens back to a long-standing conflict in dealing with Oracle and
mixed-case or reserved identifier names, to wit: In order to ensure that table
names that happen to be reserved keywords can be used, we need to enclose them
in double-quotes. But we can create tables with or without quotes, with
differing cases, and create two different tables. We may not be able to rely on
the user telling us the exactly correct name of a table in our storage model
file, but we can’t convert it to all caps without the risk of accidentally
referring to a different table!
My solution at this point was to cave and refer to the table name in all caps
in my storage model file. But now the problem is the column names! And we can’t
refer to a column name in the storage model, but we can in the mapping file, the
.msl, but we can’t simply generate the mapping file, change the
column names to all caps, and have it compile. What I ended up doing was simply
referring to all of the fields in all caps in the storage model, which of course
breaks our code, making us refer to
asset.ASSET_TYPE, as well as
uglifying the constructor code for creating new objects:
/// <summary> /// Create a new Assets object. /// </summary> /// <param name="aSSET_NUMBER">Initial value of ASSET_NUMBER.</param> public static Assets CreateAssets(string aSSET_NUMBER)
One More Thing
So, those are the big things, the deal-breakers. The largest problem to me isthe idea that we can specify a table name in our storage model file, but not
column names. This seems entirely too half-baked to me, but maybe I just don’t
understand the conceptual tactics behind a move like that.
And I just noticed this as I was signing off, a quick bizarre thing I wanted
to try:
var query = context.Assets.Where( a => a.ASSET_TYPE.Contains("A") ).Take(10);
Take the top ten items that have an uppercase A in them. Simple enough,
right? Nope. A rewriting of the generated SQL:
SELECT asset_number, asset_type FROM tblAsset WHERE ((INSTR('A', asset_type)) >0) AND ( ROWNUM <= (10) )
This is a mess. First off, that
ROWNUMclause is not going to do
what we expect, no matter what the rest of the query is. Secondly,
INSTRtakes its parameters in the reverse order.
Little things like this are going to be the hell Oracle would have to go through
to get a decent provider out there for Entity Framework, and I don’t even envy
them a little bit.
One more thing I want to say about all of this. The work I did above took
seven hours, a lot of Googling, a lot of searching through documentation, and a
lot of guessing. The following is how everything above would be handled in my current favorite Ruby ORM.
class Asset include DataMapper::Resource property :asset_type, String property :asset_number, String end query = Asset.get :asset_type => 'TEST ASSET TYPE'
This is not to compare languages or ideologies, but methodologies. Simplicity
always trumps complexity in the software engineering world. Always always
always. Make Entity Framework easier for people to use, and it could be a
godsend for shops that want a Microsoft-written ORM solution.
I’ll try and answer any questions anyone has, but this is literally the
maximum scope of what I was able to accomplish. I’ll probably throw myself back
at it later this weekend.
This entry was written by Ardekantur, posted on
August 8, 2008 at 11:07
am, filed under Concepts, Configuration Files, Experiments, Software Design, Tutorials and tagged .net, eforacleprovider, entity
framework, oracle. Bookmark the permalink. Follow any comments here with the RSS feed for this post. Post a comment or
leave a trackback: Trackback URL.
相关文章推荐
- Oracle Data Provider for .NET 的使用经验
- dotConnect for Oracle控件免费下载及使用方法
- WP移动设备压缩与解压控件Xceed Zip for .NET Compact Framework控件下载及详细介绍使用方法
- The DataDirect provider for Oracle调用存储过程使用Cursor类型参数
- Entity Framework DbSet<T>之Include方法与IQueryable<T>扩展方法Include的使用
- Oracle Data Provider for .NET 的使用经验(3)
- Comparing the Microsoft .NET Framework 1.1 Data Provider for Oracle and the Oracle Data Provider for .NET
- error 0152: No Entity Framework provider found for the ADO.NET provider with invariant name 'System.
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
- EF Provider for Access/ODBC 以及ADO.Net Entity Framework 与Linq to SQL的比较和适用场景:
- Oracle Entity Framework For Visual Studio 2010
- Oracle Data Provider for .NET的使用(二)-驱动更换与注意事项
- 解决 No Entity Framework provider found for the ADO.NET provider
- EF Provider for Access/ODBC 以及ADO.Net Entity Framework 与Linq to SQL的比较和适用场景
- 使用 Entity Framework Power Tool 报错 0×80070057 解决方法
- Oracle Data Provider for .NET 的使用经验
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
- Oracle Data Provider for .NET 的使用经验(1)
- Oracle Data Provider for .NET 的使用经验(2 )
- Entity Framework for Oracle 基本配置