I need to combine in one application
code generated from DB to EDMX file before compilation and
code generated and compiled during runtime by application itself, where generated code uses CodeFirst to access DB.
Remark: Codes in 1. and 2. have different DbContexts, access same database, but different tables.
It looks, that when I am using instances of type 1. and 2. in different transaction scopes, everything works fine. But when I try to use them together in one transaction scope, I get error (in case when EDMX is called first)
System.Reflection.TargetInvocationException: Exception has been thrown by the ta
rget of an invocation. ---> System.Data.ProviderIncompatibleException: An error
occurred while getting provider information from the database. This can be cause
d by Entity Framework using an incorrect connection string. Check the inner exce
ptions for details and ensure that the connection string is correct. ---> System
.Data.ProviderIncompatibleException: **The provider did not return a ProviderManif
estToken string.** ---> System.Transactions.TransactionException: **The operation is
not valid for the state of the transaction.**
and error (in case when CodeFirst is used first)
System.Data.MetadataException: Schema specified is not valid. Errors:
(0,0) : error 0175: **The specified store provider cannot be found in the configur
ation, or is not valid.**
at System.Data.Metadata.Edm.StoreItemCollection.Loader.ThrowOnNonWarningErrors()
To complicate my situation even more I have to add this: described behaviour I have only in case when DB is on remote server. If I am working with local DB, everything looks OK. My suspicion is that Distributed Transaction Coordinator can play its role...
Main question: is it possible to combine EDMX and CodeFirst in one TransactionScope. If yes then how?
Any help would be appreciated. Milos
CodeFirst creates an EDMX based on your classes and it's not possible to load an exisiting edmx file. However you can generate classes from your database (e.g. using EF Power Tools) and configure your model so that the EDMX generated by your CodeFirst app is the same as the one you would like to load. You can use TransactionScope with Entity Framework. The error messages you are getting are not related to transaction scope but to a missing or incorrectly used provider.
I used code first to save to two different databases came up with errors connection string was wrong so i did this and it worked....
try
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
MegaBotExtractorDBContext2 db = new MegaBotExtractorDBContext2();
MegaBotExtractorDBContext db1 = new MegaBotExtractorDBContext();
FullUri newUri = new FullUri();
HostUri NewHostUri = new HostUri { HostUriName = "google10.com" };
db1.HostUris.Add(NewHostUri);
db1.SaveChanges();
using (TransactionScope ts2 = new TransactionScope(TransactionScopeOption.RequiresNew))
{
db.FullUris.Add(newUri);
db.SaveChanges();
ts2.Complete();
ts.Complete();
}
}
}
catch { }
Related
I'm having the following error executing this piece of code:
private bool _updateList(SysInfo _sysInfo, List<pList> _pList)
{
try
{
foreach (var p in _pList)
{
_context.spUpdatePListApprovalFlow(p.countryID, _sysInfo.User.JobRoleID, p.src, p.id, p.status, _sysInfo.User.Username);
}
return true;
}
catch (Exception ex) //debug only
{
throw; //throws error to the main try catch
}
}
ERROR
The operation could not be performed because OLE DB provider "MSDASQL"
for linked server "AS400_LINKEDSRV" was unable to begin a distributed
transaction.
However, everything works fine when I run the Stored Procedure in SQL Management Studio:
exec [dbo].[spUpdatePListApprovalFlow]
#CountryID = 123456,
#UserTypeID = 23456,
#Src = 1,
#Id = '123456789',
#Status = 30,
#Username = 'username'
I'm tired of digging for an answer nothing works... Few things I've tried:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
insert multiple transactions in the stored procedure
This sp has 2 sub stored procedures on it. One that writes into a table of the application's database, and another that updates a table in as400.
In EF6 stored procedures are called in an explicit transaction, by default. You can turn this off for a particular DbContext instance by changing its configuration after creating it, or for all instances of a DbContext type by changing it in the constructor. EG
using (var db = new Db())
{
db.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
//. . .
}
See: https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.dbcontextconfiguration.ensuretransactionsforfunctionsandcommands
Ok, after half a day trying to solve this I've finally solved it.
Resolution
Downgraded from Entity Framework 6 to Entity Framework 5 and the
distribuited transactions error has gone.
Just pay attention, if you're going to do this, you have to change some usings in your code. ( in auto generated code in the Data Model as well)
EF 6 uses
using System.Data.Entity.Core.Objects
EF 5 uses
using System.Data.Objects;
If you don't need distributed transactions you can try to disable them in the settings of the linked server:
EXEC master.dbo.sp_serveroption
#server=N'AS400_LINKEDSRV',
#optname=N'remote proc transaction promotion',
#optvalue=N'false'
Refer to this Microsoft page on Linked Servers.
Your System Administrator and/or DBA will probably need to make changes to address the missing linked server definition to your AS/400 server.
Another possible issue is that the AS/400 server (from IBM) lacks software support for the OLE DB data sources. This too would be something that the System Administration staff may need to address.
I'm trying to create a class to perform work on the database and have the need (or preference) to use a combination of DbContext and good old fashioned ADO. Why, well EF is great for simplifying a great deal of code but ADO still has many uses for more complex methods that EF cannot yet handle.
This link on MSDN states that I can pass an existing SqlConnection to my context as follows:
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var context = new SampleContext(conn, contextOwnsConnection: false))
{
// Do Something
}
}
Now I'm using Database-First so this constructor doesn't appear as standard. I therefore created a new Partial Class file and created the appropriate constructor as follows:
public partial class MyEntities : DbContext
{
public MyEntities(System.Data.Common.DbConnection conn, bool contextOwnsConnection = false)
: base(existingConnection: conn, contextOwnsConnection: contextOwnsConnection)
{
}
}
However, when I run the code the moment it hits a call to the new DbContext constructor, I get the following UnintentionalCodeFirstException() error thrown by OnModelCreating in my EDMX file:
"Code generated using the T4 templates for Database First and Model First development may not work correctly if used in Code First mode. To continue using Database First or Model First ensure that the Entity Framework connection string is specified in the config file of executing application. To use these classes, that were generated from Database First or Model First, with Code First add any additional configuration using attributes or the DbModelBuilder API and then remove the code that throws this exception."
Am I missing something obvious here, or can it just not be done with Database-First?
Clearly, I could just use two connections, one for my SqlConnection object, and another for my DbContext object but if I can, naturally I'd prefer to use a single connection if possible.
Any and all help greatly appreciated. For full disclosure, I'm using SQL-Server 2012, .NET 4.5.1, C# and EF6.0.2.
Connection strings used by the designer are not regular connection strings. Rather they are EntityConnection strings. The difference is that entity connection strings contain additional information about where to find metadata describing the model which is in form of the edmx at design time - read more here. Code First uses just regular connection strings since it builds the model on the fly based on the code. So, the UnintentionalCodeFirstException is preventing the user from using CodeFirst functionality with edmx models because the model is specified in the edmx and not in the code and if it was allowed you would effectively end up using two different models (one from edmx and one built from the code) which very likely won't be in sync which would result in weird behavior or even could lead to data corruption and crashes/exceptions.
Since the EntityConnection is derived from DbConnection and just wraps regular connection you can use it in places where you would use the provider connection. Alternatively you can access the wrapped provider connection using the StoreConnection provider on the EntityConnection.
I know this is an old thread, but later versions of Entity Framework actually can handle a shared connection, so I offer this as an alternative answer.
You can initialize an instance of the entity container with a shared connection. Use the EntityConnection(MetadataWorkspace workspace, DbConnection connection, bool entityConnectionOwnsStoreConnection) overload and specify false for the entityConnectionOwnsStoreConnection parameter. Then pass it into your context constructor as the existing connection. The EntityConnection will then prevent the connection from being automatically closed and disposed with the context.
Example:
using (var conn = new SqlConnection("..."))
{
conn.Open();
// Execute some ADO queries.
var md = new MetadataWorkspace(new[]{"res://*/SampleModel.csdl","res://*/SampleModel.ssdl","res://*/SampleModel.msl"}, new[]{System.Reflection.Assembly.GetExecutingAssembly()});
// Create the EntityConnection so the existing connection is not disposed.
var ec = new EntityConnection(md, conn, false);
using (var context = new SampleContext(conn, contextOwnsConnection: false))
{
// Do something using the entity context.
}
// Entity context is disposed but connection remains open.
// Do more ADO stuff.
}
Yes, it was a pain to figure out this stuff by examining System.Data and Entity Framework source code.
This pattern may be used within a TransactionScope to prevent escalation to a distributed transaction by virtue of using the same database connection.
I am using VS2012.
When I go an create a .edmx file, it creates the following structure:
->Model.edmx
-->Model.Context.tt
-->Model.Designercs
-->Model.edmx.diagram
-->Model.tt
From my understanding, VS2012 generates T4 templates (the .tt files) which generate the entities and context. The default entities generated in VS2012 are POCO entities.
I am able to add a table to the Model just fine.
When I do a compile, I get no errors.
When
I do the following:
Model dbContext3 = new Model();
var result = (from dd in dbContext3.tblWMt
select dd).ToList();
I get the following message at run time from System.Data.MetadataException :
{"Unable to load the specified metadata resource."}
Any idea what may be going wrong. I did check the connection string and that looks correct.
As mentioned, I was able to even add a table from the designer just fine.
Below is the connection string:
metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="data source=.\Sql2012;initial catalog=Phig;persist security info=True;user id=sa;password=S4343;multipleactiveresultsets=True;application name=EntityFramework
When using this code on a SqLite file database, it works fine.
using (var ctx = new Test2010Entities())
{
string s = "CREATE TABLE 'Company' ([Id] integer PRIMARY KEY AUTOINCREMENT NOT NULL, varchar(50) NOT NULL);";
ctx.ExecuteStoreCommand(s);
ctx.Companies.AddObject(new Company { Code = "_1" });
ctx.Companies.AddObject(new Company { Code = "_2" });
ctx.SaveChanges();
foreach (var c in ctx.Companies.ToList())
{
Console.WriteLine(c.Code);
}
}
But when runnning this code on a SqLite 'In Memory' database (Data Source=:memory:;Version=3;New=True;) , I get this exception:
Unhandled Exception: System.Data.UpdateException: An error occurred
while updating the entries. See the inner exception for details. --->
System.Data.SQLite.SQLiteException: SQL logic error or missing
database no such table: Company
Note this is tested with VS 2010, EF 4.4.0.0 and sqlite-netFx40-setup-bundle-x86-2010-1.0.84.0
::: UPDATE :::
As Simon Svensson suggested, opening the connection before any other commands does do the trick:
ctx.Connection.Open();
This happens when your ORM closes your connection, and reopens it. That will reset the sqlite in-memory database to its default state; i.e. empty.
The same thing happens with NHibernate unless you set connection.release_mode = close (the default is after_transaction.
I'm not familiar with Entity Framework, but I expect a similar setting or using the DataContext(IDbConnection) constructor which is documented as "If you provide an open connection, the DataContext will not close it."
The same documentation also states "In a System.Transactions transaction, a DataContext will not open or close a connection to avoid promotion." which may be a cleaner solution.
Using some Reflector magic shows that it's SQLiteConnection.Open that calls (via SQLite3.Open) sqlite3_open_interop (if you're using the NuGet sqlite package). This shows that you get a new empty in-memory database everytime you call SQLiteConnection.Open.
I use EntityFramework in a project to connect to a Mysql database. The provider is Devart Dot.connect.
This application needs to connect to a database using connexion parameters given by the user at runtime. This includes of course the Mysql Database name.
I used the EntityConnectionStringBuiler and EntityConnection classes to build-up and store the custom connexion parameters.
The problem is that even with such given parameters, the application always connect to the database named when designing the EntityModel using the visual studio wizard.
What is very strange is that when debuging and checking the status of the ObjectContext, the custom connexion parameters are correctly used...
It makes me mad !!!!!
Any clue ?
After spending one day on this issue, I finally came to understand that the problem was coming from the model.edmx file.
In this file, you have one line per EntitySet.
On each EntitySet element there is an attribute called schema. In case of SQL Server this attribute is set to the related table schema :
EntitySet Name="annee_civile"
EntityType="openemisModel.Store.annee_civile"
store:Type="Tables" Schema="mydatabase" />
If you provide the name of the Schema when constructiong you own EntityConnection, it seem that there is a conflict and that finally, the Schema defined in the edmx file will be used even if you specified another one in the connection parameters.
The solution is simply to remove the name of the schema in the edmx file.
THIS WORKS FOR MYSQL, probably not when connecting to a SQL server.
EntitySet Name="annee_civile"
EntityType="openemisModel.Store.annee_civile"
store:Type="Tables" Schema="" />
The EntityConnectionStringBuilder :
string providedString = "User Id=xxxx;Password=xxx;Host=xxxx;Database=anydatabasename";
EntityConnectionStringBuilder entityConnBuilder = new EntityConnectionStringBuilder();
entityConnBuilder.Provider = "Devart.Data.MySql";
entityConnBuilder.Metadata = #"res:///OpenEmisModel.csdl|res:///OpenEmisModel.ssdl|res://*/OpenEmisModel.msl";
entityConnBuilder.ProviderConnectionString = providedString;
The EntityConnection and the object context using it:
EntityConnection entityConnexionEmis = new EntityConnection(entityConnBuilder.ConnectionString);
objectcontextEntities testingContext = new objectcontextEntities(entityConnexionEmis);
The software is now able to connect to any database name.
Hope this helps.
Reference the dll Devart.Data.MySql.Entity.EF6.dll in the project.
Somewhere when your application is starting up and before database operations take place, add the following:
var config = MySqlEntityProviderConfig.Instance;
config.Workarounds.IgnoreSchemaName = true;
You will need to reference:
using Devart.Data.MySql.Entity.Configuration;