Using both Entity Framework and SqlConnection? - c#

Background
I'm working on a project which contains both legacy code and Entity Framework code. I was advised to use a specific dataservice method to operate on a record from the database. The record was retrieved via Entity Framework, and I passed the PK into the dataservice function to perform the operation.
Preconditions for success and failure
If the network was up, both DB calls (entity and SQL) would succeed. If the network went down, then came back up and this code was executed, then it would retrieve the locked records with entity framework but then fail with the SqlException below.
This got me thinking, what is going on here that might cause the SqlConnection to fail despite EF being able to make the connection.
Code Samples
A code sample follows:
public void HandleNetworkBecomesAvailable() {
_entityFrameworkDataService.ReleaseRecords();
}
EntityFrameworkDataService.cs
public void ReleaseRecords()
{
using (var context = new Entities()) // using EntityConnection
{
var records = context.Records.Where(
record => record.IsLocked).ToList();
foreach (var record in records)
{
_sqlConnectionDataService.UnlockRecord(record.ID);
}
}
}
SqlConnectionDataService.cs
public void UnlockRecord(int recordId)
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Sqlconnection"].ConnectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = #"UPDATE [Records] SET [IsLocked] = 0";
//etc
command.ExecuteNonQuery();
}
}
}
App.config
<add name="EntityConnection" connectionString="metadata=res://*/FooDatabase.csdl|res://*/FooDatabase.ssdl|res://*/FooDatabase.msl;provider=System.Data.SqlClient;provider connection string="data source=RemoteServer;initial catalog=FooDatabase;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
<add name="SqlConnection" connectionString="Server=RemoteServer;Database=FooDatabase;Trusted_Connection=True" />
Now, after discussing with my coworkers, I ended up moving the logic into the entity framework dataservice and doing the work there. But I'm still not quite sure why the connection kept failing.
Edit: The actual error is:
An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code
Additional information: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
Inner Exception:
The network path was not found
But Entity Framework is using the same network path, as can be seen in the two connection strings in the App.config.

Could you be benefiting from entity framework's new resiliency, where it retries transparently? If the error is intermittent, you won't even know it retried, whereas ADO.net is letting you know it fails as soon as it fails. Just checking...

Related

DbConnection with Unity and Entity Framework on file database

Problem I'm dealing with, is weird error :
SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 52 - Unable to locate a Local Database Runtime installation. Verify that SQL Server Express is properly installed and that the Local Database Runtime feature is enabled.)
it happens whenever any method with db is called, like:
foo()
{
return _dbContext.data.ToList();
}
File db was created automatically based on code first approach and connection string:
<add name="Context"
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\RestApi.Services.Context.mdf;Initial Catalog=RestApi.Services.Context;Integrated Security=True"
providerName="System.Data.SqlClient" />
I can connect with no errors to that file by VS server explorer.
On same PC I've runned several others apps with file db without any errors.
When I watch "Context" var in debbuger it seems connected to proper DB, but have error on workspaceID.
Now I'm stuck and don't have any idea how to fix it. :(
UnityConfig:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<Context, Context>(new PerThreadLifetimeManager());
container.RegisterType<IXService, XService>();
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
Context class:
public class Context : DbContext
{
public Context() : base("name=Context")
{
}
public DbSet<X> Xs{ get; set; }
public DbSet<Z> Zs{ get; set; }
public DbSet<Y> Ys{ get; set; }
}
EDIT
File Db was not the problem, I've tried with normal db connection string, and errors still occur.
I've tried many different solutions and no one works :(
now after change in UnityConfig:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<DbContext, Context>();
container.RegisterType<IXService, XService>();
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
first db read:
InvalidOperationException: The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.
next ones:
NullReferenceException: Object reference not set to an instance of an object.
EDIT2
Docker support was causing problems ;/ I'll upload solution when I find one
make sure that connectionstring data source is valid server name. if server name is valid then follow this instruction, this may help you.
Open "SQL Server Configuration Manager"
Now Click on "SQL Server Network Configuration" and Click on "Protocols for Name"
Right Click on "TCP/IP" (make sure it is Enabled) Click on Properties
Now Select "IP Addresses" Tab -and- Go to the last entry "IP All"
Enter "TCP Port" 1433.
Now Restart "SQL Server .Name." using "services.msc" (winKey + r)

Why does Entity Framework try to build an already existing database?

In both my Services and WebSite Web.config file, I have the following connection string:
<connectionStrings>
<add name="MyDBConnect" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;Initial Catalog=MyDB;User Id=tester;Password=abc123*123;" providerName="System.Data.SqlClient" />
</connectionStrings>
I manually ran my database build script and have confirmed in the SSMS UI: (LocalDB)\MSSQLLocalDB (SQL Server 13.0.40001 - 8Protons) > Databases > MyDB
While running the project and going to the login screen, an exception is thrown at:
var entity = GetAll().Include(p => p.Role).FirstOrDefault(p => p.Email == userName && p.Password == encryptedPassword && p.IsActive);
with the following message
An exception of type 'System.Data.SqlClient.SqlException' occurred in
EntityFramework.dll but was not handled in user code Additional
information: CREATE TABLE permission denied in database 'MyDB'.
Why is the solution trying to CREATE a table when it already exists? So I went to the table is SSMS and elevated this user's permissions to create a table. The error that now gets thrown is:
An exception of type 'System.Data.SqlClient.SqlException' occurred in
EntityFramework.dll but was not handled in user code Additional
information: There is already an object named 'MyTable' in the
database.
For context, this is after I've cloned someone's EF solution, built it, and am attempting to sign in to a log-in page that the solution is running. So this is a fresh solution on my local machine.
Review the constructor for your database context. For example,
public MyDBContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
this.Database.CommandTimeout = 60;
IDatabaseInitializerCreator creator = new DatabaseInitializerCreator();
Database.SetInitializer(creator.Create());
}
The last two lines will make sure the database and its tables are created, if not already existing and matching exactly what exists.

Entity Framework Connection String "The Server was not found"

I have set up a Code First using the following DbContext
public class MyDatabaseDbContext : DbContext
{
public MyDatabaseDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
public MyDatabaseDbContext()
: base("MyDatabase")
{
}
public DbSet<MyTable> MyTables { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
I have also set up the connection string to look at the (Local) database
<connectionStrings>
<add name="MyDatabase"
connectionString="Server=(local);Database=MyDatabase;Trusted_Connection=True;MultipleActiveResultSets=true"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
Also set up the initializer in Global.asax
Database.SetInitializer<MyDatabaseDbContext>(new DropCreateDatabaseAlways<MyDatabaseDbContext>());
I then run the application and call the DbContext (in my case from the controller)
var dbContext = new MyDatabaseDbContext();
var myTableResults = dbContext.MyTables.ToList();
I get the follow error message
An exception of type 'System.Data.SqlClient.SqlException' occurred in EntityFramework.dll but was not handled in user code
Additional information: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 50 - Local Database Runtime error occurred. Cannot get a local application data path. Most probably a user profile is not loaded. If LocalDB is executed under IIS, make sure that profile loading is enabled for the current user.
On Debugging and looking at the dbContext variable > Database > Connection > ConnectionString Property I see the following:
"Data Source=(localdb)\v12.0;AttachDbFilename=|DataDirectory|MyDatabase.mdf;Initial Catalog=MyDatabase;Integrated Security=True;MultipleActiveResultSets=True"
Questions
Why is it pointing to the (localDb)\v12.0 database and not my connection string?
Even so, Why is it not creating the database there anyway as this is on my dev machine?
Is there some kind of convention which I have forgotten about which I need to set.
Your connection string needs to be named MyDatabaseDb
OR
your context class needs to be named MyDatabaseContext.
Entity Framework's convention is for the context class to look for a connection string with the same name + Context. The Db in your class name is extraneous.

Call Stored Procedure on specific database with MVC Application connecting to 2 databases

I have ASP.NET MVC application running with multiple database, one of which holding the stored procedures. My application along with stored procedure was working fine until I added another database connection string in web.config
Web.config:
<connectionStrings>
<add name="AppDbConnection" connectionString="xyz" providerName="System.Data.SqlClient" />
<add name="CIDDbConnection" connectionString="abc" providerName="System.Data.SqlClient" />
</connectionStrings>
I have stored procedure on AppDbConnection
Now I am getting error
Could not find stored procedure 'GetAllFunction'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: Could not find stored procedure 'GetAllFunction'.
C# Code calling stored procedure:
public List<GetAllFunction_SP_Map> GetAllFunction_From_StoreProcedure()
{
List<GetAllFunction_SP_Map> query;
using (var dbContext = new FunctionContext())
{
query = dbContext.Database.SqlQuery<GetAllFunction_SP_Map>("exec GetAllFunction").ToList();
}
return query;
}
DbContext:
public class FunctionContext : BaseContext<FunctionContext>
{
public System.Data.Entity.DbSet<App.DAL.Model.GetAllFunction_SP_Map> GetAllFunction_SP_Map { get; set; }
}
I have Data Access of two database in separate application folder and both have their DbContext
My question is how to solve this error, I believe somehow I need to tell in C# to use specific database from where I am calling the stored procedure.
Many thanks in advance
Just adding a connection string would not cause this issue. I guess, what happened in addition to that, is your FunctionContext did get modified as well, to use the new connection string. Try this:
using (var dbContext = new FunctionContext("AppDbConnection"))
{
query = dbContext.Database.SqlQuery<GetAllFunction_SP_Map>("exec GetAllFunction").ToList();
}
... without knowing what else could have been modified.

How can I check the connectivity in a Linq2Sql app so it doesn't freeze if it fails?

So I've been using LINQ to SQL (dbml) for my C# projects for a bit now as it makes integrating SQL pretty easy for me.. the only thing is everything is so automated that I don't know how to actually edit things.
Using LINQ to SQL makes it so that it automatically connects to the database IP with user and pw in the connection string it creates in the config file but say the database isn't up.. or i want to change IPs.. the app freezes on start up.
How can I test for connectivity before having it automatically connect? I can't seem to find where in the code it does this exactly.
Your settings for the Entity, I am rusty on Linq to SQL but think it is similar, are in the App.Config on the project where you CREATED you Linq to SQL model. They are similar to this(using Entity Model):
< connectionStrings>
< add name="Example" connectionString="metadata=res://*/ExampleDB.csdl|res://*/ExampleDB.ssdl|res://*/ExampleDB.msl;provider=System.Data.SqlClient;provider connection string="data source=ACTUALSERVER;initial catalog=ACTUALDATABASE;persist security info=True;user id=(SET USER HERE);password=(SET PASSWORD HERE);multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
< /connectionStrings>
The important part for connection is the connection string though:
"data source=ACTUALSERVER;initial catalog=ACTUALDATABASE;persist security info=True;user id=(SET USER HERE);password=(SET PASSWORD HERE);
You can try to alter this to different connection strings if you want, and keeping the metadata the same. For differenent environments like "Dev", "QA", "UAT", "PROD" etc... And then copy and paste the connection block starting with the '< add name="' and till the end portion of 'providerName='(thing)' />. Then just alter the connection string and give it a different name. Then you could have the calling code use a different context or connection like:
using(MyContext context = new MyContext())
{
context.Connection = (new connection)
(your data return method)
}
You may be able to do this directly in the constructor of your context(MyContext). Cannot recall. Generally I usually set up multiple configs "DEV", "QA", "UAT", "PROD" and have them build for different environments for a service. You can build a connection string manually but dynamic connection strings can be a pain as you as a developer now need to ensure a few things:
The model of a Dev environment EXACTLY matches another with it's objects in your model. If not goodbye code return.
If you are invoking a set user that you are ensuring that your user has rights on certain environments
That you are not putting the integrity of your code at risk by showing too much publicly for user settings.
(All assuming you're using Sql Server)
Expanding on djangojazz's answer.
public void TestDbConnection()
{
Task.Factory.StartNew(() =>
{
bool isAvailable = false;
using(MyContext context = new MyContext())
{
var connection = ((IObjectContext)context).Connection as SqlConnection;
try
{
connection.Open();
isAvailble = true;
}
catch (Exception ex)
{
}
}
TestDbConnectionComplete(isAvailable);
});
}
public void TestDbConnectionComplete(bool isAvailable)
{
}

Categories