Entity framework 6 without config file? - entity-framework

I have an application that can not use a config file and has to set up the connectionstring for the entity context by code (with EntityConnectionStringBuilder).
The problem comes however with this:
No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SqlClient'.
Since I can not use the standard app.config file, am I screwed in EF6? It was not a problem in EF4 if I recall correctly.
So the settings inside the entityFramework-tag is something I wish to set in code.
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>

I'm using EF 6 without an App.config file at all I just pass a connection string to my DBContext (well the connection is read out of a config file elsewhere but that's up to you). Just Remove all the EF stuff from the config file.
Here's how I got it to work.
public partial class MyDbContext : DbContext, IMyDbContext
{
public MyDbContext(string connectionString,
DbValidationMode validationMode = DbValidationMode.Enabled,
DbLazyLoadingMode lazyLoadingMode = DbLazyLoadingMode.Disabled,
DbAutoDetectMode autoDetectMode = DbAutoDetectMode.Enabled)
: base(((EntityConnectionStringBuilder)new EntityConnectionStringBuilder()
{
Provider = "System.Data.SqlClient",
ProviderConnectionString = connectionString,
Metadata = #"res://*/Contexts.Test.MyModel.csdl|res://*/Contexts.Test.MyModel.ssdl|res://*/Contexts.Test.MyModel.msl"
}).ToString())
{
this.Configuration.ValidateOnSaveEnabled = validationMode.Equals(DbValidationMode.Enabled);
this.Configuration.LazyLoadingEnabled = lazyLoadingMode.Equals(DbLazyLoadingMode.Enabled);
this.Configuration.AutoDetectChangesEnabled = autoDetectMode.Equals(DbAutoDetectMode.Enabled);
}
... Etc
Then I just inject this context into all my services.
I'm using Database First design so I found it easier to modify the T4 Templates.
There may be nicer ways of doing this but I've not ran into any problems at all.

In EF6 you can use Code-based Configuration for Entity Framework specific setup. (Also see How to add entity framework 6 provider in code?). Then you can build connection string and pass it to the ctor of the context.

Related

Trying to use DDtek Datadirect Sybase drivers as a provider for Enttiy Framework 6, can't get it configured correctly

Trying to use DDtek Datadirect Sybase drivers as a provider for Enttiy Framework 6, can't get it configured correctly..
It looks like in 3.3 there is no DDtek.Sybase.Entity,
We have a trial version of 4.2 which has the DLL, so I've installed that on.
Here is my providers section of the web.config, where I think the error lives
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory,
EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices,
EntityFramework.SqlServer" />
<provider invariantName="DDTek.Sybase.4.2" type="DDTek.Sybase.Entity.ProviderServices, DDTek.Sybase.Entity,
Version=4.2.0.0, Culture=neutral, PublicKeyToken=c84cd5c63851e072" /
</providers>
</entityFramework>
and here is my connection string
<add name="DefaultConnection" connectionString="host='XXXX.XXX';Pooling=true;Port='6000';UID='XXXXX';Password=XXXXX;Database='XXXX';Min Pool Size=5;Load Balance Timeout=30;Connection Timeout = 30000;Max Pool Size=50;Workstation ID='SPN'; Clone Connection If Needed =true; Fetch Buffer Size = 40960" providerName="DDTek.Sybase.4.2" />
The connection string, minus the providername bit works in 3.3, non EF.
Here is the error I'm getting...
The Entity Framework provider type
'DDTek.Sybase.Entity.ProviderServices, DDTek.Sybase.Entity,
Version=4.2.0.0, Culture=neutral, PublicKeyToken=c84cd5c63851e072'
registered in the application config file for the ADO.NET provider
with invariant name 'DDTek.Sybase.4.2' could not be loaded. Make sure
that the assembly-qualified name is used and that the assembly is
available to the running application. See
http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
Looking at more documentation I changed the name to DDTek.Sybase (default) instead of DDTek.Sybase.4.2 (recommended fro multiple versions installed (which there are, but only one supports EF)
and this is the error I get instead
The Entity Framework provider type
'DDTek.Sybase.Entity.ProviderServices, DDTek.Sybase.Entity,
Version=4.2.0.0, Culture=neutral, PublicKeyToken=c84cd5c63851e072'
registered in the application config file for the ADO.NET provider
with invariant name 'DDTek.Sybase' could not be loaded. Make sure that
the assembly-qualified name is used and that the assembly is available
to the running application. See
http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
Has anyone successfully set this up using the Progress/DataDirect drivers?
I'm 100% noob to Entity Framework, so no idea is too small, or unappreicated
The DataDirect Drivers do not support EF 6.0 as they previously told me, it
only supports 5.0.
So I converted it to work with MSDB, in like 10 min (Most of which was commenting out bits of Sybase + ddtek stuff)
The new connectionstring looked like this
<add name="DefaultConnectionMSold" connectionString="Data Source=XXXXXXXXX;Initial Catalog=my_project;Integrated Security=True" providerName="System.Data.SqlClient"/>

Sample for Entity Framework 6 + Code First + Oracle 12c

I have a problem with a Visual Studio solution using Entity Framework 6 + Code First + Oracle 12c. I'm not sure it is properly configured, or if I missed something simple.
I tried to look for a sample project as a start, but was not able to find - google search, stackoverflow etc.
Is there a minimalistic sample project somewhere, which tries to create the database when runs?
Update: Just to make sure, I'm not asking anyone to create a sample for me. Before I'll do it, I want to make sure there is really no existing sample (which is strange for me, but very well might be the case).
I managed to create a working sample. Found some (not so) documented strange behaviors resulting in run time errors along the way.
Here is the full sample source: https://drive.google.com/file/d/0By3P-kPOnpiGRnc0OG5ZTDl6eGs/view?usp=sharing&resourcekey=0-ecT1EU81wJOQWokVDr_r9w
I created the sample with Visual Studio 2013. Used nuget to pull
EntityFramework 6.1.3
Official Oracle ODP.NET, Managed Entity Framework Driver 12.1.021
The important parts are
Program.cs
Context.cs
TestEntity.cs
App.config
I omit
packages.config
AssemblyInfo.cs
csproj, sln files
I also omit namespaces.
using System.Data.Entity;
public class Program
{
private static void Main(string[] args)
{
string connStr =
"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=***server***)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=***SERVICE***)));Persist Security Info=True;User ID=***User***;Password=***password***";
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
//Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
Context context = new Context(connStr);
TestEntity te = new TestEntity();
te.Id = 1;
te.Name = "Test1";
context.TestEntities.Add(te);
context.SaveChanges();
}
}
using System.Data.Entity;
public class Context : DbContext
{
public Context(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
public virtual DbSet<TestEntity> TestEntities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("OTS_TEST_EF");
modelBuilder.Entity<TestEntity>()
.Property(e => e.Id)
.HasPrecision(9, 2);
base.OnModelCreating(modelBuilder);
}
}
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("TestEntity")]
public class TestEntity
{
[Column(TypeName = "number")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public decimal Id { get; set; }
[StringLength(100)]
public string Name { get; set; }
}
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false"/>
<section name="oracle.manageddataaccess.client"
type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<entityFramework>
<!--<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>-->
<providers>
<!--<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>-->
<provider invariantName="Oracle.ManagedDataAccess.Client"
type="Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices, Oracle.ManagedDataAccess.EntityFramework, Version=6.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="Oracle.ManagedDataAccess.Client"/>
<add name="ODP.NET, Managed Driver" invariant="Oracle.ManagedDataAccess.Client" description="Oracle Data Provider for .NET, Managed Driver"
type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
</DbProviderFactories>
</system.data>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<publisherPolicy apply="no"/>
<assemblyIdentity name="Oracle.ManagedDataAccess" publicKeyToken="89b483f429c47342" culture="neutral"/>
<bindingRedirect oldVersion="4.121.0.0 - 4.65535.65535.65535" newVersion="4.121.2.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<!--<oracle.manageddataaccess.client>
<version number="*">
<dataSources>
<dataSource alias="SampleDataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=INFOTEST))) "/>
</dataSources>
</version>
</oracle.manageddataaccess.client>-->
<!--<connectionStrings>
<add name="OracleDbContext" providerName="Oracle.ManagedDataAccess.Client"
connectionString="Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = INFOTEST)));Persist Security Info=True;User ID=user;Password=password"/>
</connectionStrings>-->
</configuration>
The strange thing I found on the way:
Adding any of the following TypeNames will result in "Sequence contains no matching element" error.
/*[Column(TypeName = "numeric")]*/
/*[Column(TypeName = "number(18,0)")]*/
/*[Column(TypeName = "number(18,2)")]*/
Indicating precision with scale 0
modelBuilder.Entity<TestEntity>().Property(e => e.Id).HasPrecision(9, 0);
Will result in
Schema specified is not valid. Errors:
(7,12) : error 2019: Member Mapping specified is not valid. The type 'Edm.Decimal[Nullable=False,DefaultValue=,Precision=9,Scale=0]' of member 'Id' in type 'EF6_Oracle12c_CF.TestEntity' is not compatible with 'OracleEFProvider.number
Omitting the
modelBuilder.HasDefaultSchema("OTS_TEST_EF");
line will result in
ORA-01918: user does not exists
It is also happened that I got
ORA-00955: name is already being used by existing object
or
Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations.
I managed to overcome those by enabling the
Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
line, instead of the DropCreateDatabaseIfModelChanges mode.
This has the a good sample if you are still interested . It is available on 11 g .
http://www.oracle.com/webfolder/technetwork/tutorials/obe/db/dotnet/CodeFirst/index.html
Here's a link to a sample from Oracle on using EF Code First, Migration and Visual Studio.
Oracle Learning Library on EF Code First and Code First Migration
I'm actually almost finishing up a project that uses VS, 12c and EF and the link was a good starting point. There was no particular issue about 12c that I saw.
I have a test project on github that I used to try out examples of EF6 migrations on Oracle. The code that works for me (to programatically execute all pending migrations) is here. My use case is likely common - I need to be able to deploy my application to various environments and data centres and have it do "the right thing" to work with the environment's copy of my application database.
The important bit is
//Arrange
Configuration config = new Configuration();
DbMigrator migrator = new DbMigrator(config);
Console.WriteLine("Migrating...");
foreach (string s in migrator.GetPendingMigrations())
{
//Act
Console.WriteLine("Applying migration {0}", s);
Action act = () => migrator.Update(s);
//Assert
act.ShouldNotThrow();
}
I spent days fixing this issue... Finally I solved it:
The table did not exist. I checked many times and refreshed, but the problem was not in the table itself, it was with the sequence. Every table in Oracle creates a sequence object to increase the id. So, if you delete the table make sure to drop the sequence as well, otherwise when you migrate again, it will give you ORA-00955: name is already used by an existing object.
So, the real problem is in the sequence, not in the table. But you cannot create new sequence because it already exists. It is not deleted when you delete the table, it should be deleted manually.
I hope this will help someone.

Using connection string in Web.config when enabling code-first migrations

I have multiple connection strings in Web.config (for databases that should all have the same exact schema), and my DbContext is initialized with a connection string dynamically:
public MyDbContext(string connectionStringName) : base(connectionStringName)
{
}
I do not have a default constructor for MyDbContext as it is meaningless in my case. I decide which connection string to use based on the Id value of each entity (custom sharding).
I'm trying to run enable-migrations for my DbContext, but I'm getting the following error:
The target context 'MyDbContext' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory.
I've seen a sample implementation of IDbContextFactory like so:
public class MyDbContextFactory : IDbContextFactory<MyDbContext>
{
public MyDbContext Create()
{
return new MyDbContext("connectionStringName");
}
}
How is this going to help me? Isn't the connection string still hard-coded? How could I add migrations for each database?
And how about providing default constuctor for that DbContext and then when you call scripts add-migration and update-database you may use -ConnectionStringName and -ConnectionProviderName attributes to point to database you want to use.
By the way - enable-migrations script does not do much - it addes Migrations folder to your project and Configuration class. You might do it yourself.
Best Soution is to use a separate file where you will mention list of Id values against a connection e.g in
<connectionStrings>
<add name="MyConn1"
connectionString="#your connection string"
/>
<add name="MyConn2"
connectionString="#your connection string"
/>
and then in
<appSettings>
<add key="MyConn1" value="entity1,entity2" />
<add key="MyConn2" value="entity3,entity4" />
</appSettings>
Then dynamically load your connection string in some global variable
public MyDbContext() : base(MyConnectionManager.connectionStringName)
{
}
You can do it using IoC as well. Look at the sample code.
https://github.com/aamir-poswal/CodeSample
Especially
- Bootstrapper.cs
- CRMContext.cs
- DatabaseFactory.cs which you need to customize in your context

Share EF connection string from subproject in the main project

I have two projects
MyProject //MVC 3 app
MyProject.DAL //Class Library project type
Inside MyProject.DAL there is a folder EntityModels which contains generated entity (EF Code-First approach):
namespace MyProject.DAL.EntityModels
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class myEntities : DbContext
{
public myEntities() : base("name=myEntities")
{
...
}
}
}
app.config:
<add name="myEntities" connectionString="metadata=res://*/EntityModels.DBMainModel.csdl|res://*/EntityModels.DBMainModel.ssdl|res://*/EntityModels.DBMainModel.msl;provider=..." providerName="System.Data.EntityClient" />
then, I want to use that entity in my MyProject project, so I add the same connection string in the web.config file.
But, I get the Unable to load the specified metadata resource. error. I tried make some modifications in the web.config like
<add name="myEntities"
connectionString="metadata=res://*/MyProject.DAL.EntityModels.DBMainModel.csdl|
res://*/MyProject.DAL.EntityModels.DBMainModel.ssdl|
res://*/MyProject.DAL.EntityModels.DBMainModel.msl;provider=..." providerName="System.Data.EntityClient" />
<add name="myEntities"
connectionString="metadata=res://MyProject.DAL.EntityModels.DBMainModel.csdl|
res://MyProject.DAL.EntityModels.DBMainModel.ssdl|
res://MyProject.DAL.EntityModels.DBMainModel.msl;provider=..." providerName="System.Data.EntityClient" />
<add name="myEntities"
connectionString="metadata=res://MyProject.DAL/EntityModels.DBMainModel.csdl|
res://MyProject.DAL/EntityModels.DBMainModel.ssdl|
res://MyProject.DAL/EntityModels.DBMainModel.msl;provider=..." providerName="System.Data.EntityClient" />
but nothing works. How to fix it ?
If it's code-first, you should put pure connectionString value in your appropriate .config file (You're dealing with SqlClient not EntityClient).
To find out more about ConnectionString values, take a look at http://www.connectionstrings.com/sql-server/.
For SQL Server databases, basically it is like below:
<add name="MyEntities" connectionString="Data Source=myServerName\myInstanceName;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;" providerName="System.Data.SqlClient"/>

EF4 Creating a custom DbFactoryProvider and other Db* classes

I was attempting to create a set of custom classes to create my own provider that the Entity Framework would be communicating with. I had created my custom class that inherited from the abstract class DbProviderFactory and had just begun testing to see if I could get it to talk with EF, but I ran into issues.
<configuration>
<system.data>
<DbProviderFactories>
<add name="Custom Data Provider"
invariant="CustomClient"
description=".Net Framework Data Provider for Custom"
type="CustomClient.CustomProviderFactory, CustomClient,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</DbProviderFactories>
</system.data>
<connectionStrings>
<add name="AdventureWorksEntities"
connectionString="metadata=...;
provider=CustomClient;
provider connection string="data source=.;
initial catalog=AdventureWorks;integrated security=True;
multipleactiveresultsets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
With my CustomClient defined above I thought it would be smooth sailing into Entity goodness, but when my code attempts to create a new AdventureWorksEntities object I get the following exception:
InvalidOperationException
The requested .Net Framework Data Provider's implementation does not have an Instance field of a System.Data.Common.DbProviderFactory derived type.
Looking over the available overrides for DbProviderFactory makes no mention of an Instance member. I'm not really sure why it is requiring this field if it is not part of the class/interface for DbProviderFactory. Is the fix as simple as providing a field named Instance that returns an object of my custom type?
Add this to your custom provider:
public static readonly CustomProviderFactory Instance = new CustomProviderFactory();
All build in factories have this - they are used as singleton.