Multiple queries using same datacontext throws SqlException - c#

I've search control with which I'm trying to implement search as user types something. I'm using Linq to SQL to fire queries against the database. Though it works fine usually, when user types the queries really fast some random SqlException is thrown. These are the two different error message I stumbled across recently:
A severe error occurred on the current command. The results, if any, should be discarded.
Invalid attempt to call Read when reader is closed.
Edit: Included code
DataContextFactory class:
public DataContextFactory(IConnectionStringFactory connectionStringFactory)
{
this.dataContext = new RegionDataContext(connectionStringFactory.ConnectionString);
}
public DataContext Context
{
get { return this.dataContext; }
}
public void SaveAll()
{
this.dataContext.SubmitChanges();
}
Registering IDataContextFactory with Unity
// Get connection string from Application.Current settings
ConnectionInfo connectionInfo = Application.Current.Properties["ConnectionInfo"] as ConnectionInfo;
// Register ConnectionStringFactory with Unity container as a Singleton
this.container.RegisterType<IConnectionStringFactory, ConnectionStringFactory>(new ContainerControlledLifetimeManager(),
new InjectionConstructor(connectionInfo.ConnectionString));
// Register DataContextFactory with Unity container
this.container.RegisterType<IDataContextFactory, DataContextFactory>();
Connection string:
Data Source=.\SQLEXPRESS2008;User Instance=true;Integrated Security=true;AttachDbFilename=C:\client.mdf;MultipleActiveResultSets=true;
Using datacontext from a repository class:
// IDataContextFactory dependency is injected by Unity
public CompanyRepository(IDataContextFactory dataContextFactory)
{
this.dataContextFactory = dataContextFactory;
}
// return List<T> of companies
var results = this.dataContextFactory.Context.GetTable<CompanyEntity>()
.Join(this.dataContextFactory.Context.GetTable<RegionEntity>(),
c => c.regioncode,
r => r.regioncode,
(c, r) => new { c = c, r = r })
.Where(t => t.c.summary_region != null)
.Select(t => new { Id = t.c.compcode, Company = t.c.compname, Region = t.r.regionname }).ToList();
What is the work around?

It's not something that requires MARS in your connection string?
http://msdn.microsoft.com/en-us/library/h32h3abf(VS.80).aspx

Related

Entity Framework saying invalid object name when table exists

I've had to jump in to a complex project and am making unit tests for a particular repository in a WEB API service. The database CRUD is handled by the Entity Framework.
private class IntegrationScope : AutoRollbackTransactionTestScope<DocumentRepository>
{
public IntegrationScope()
{
DependencyResolverMock = MockDependencyResolverFor<IResourceUrlBuilder, ResourceUrlBuilder>(new ResourceUrlBuilder());
LoggingProviderMock = new Mock<ILoggingProvider>();
// use real document micro service AutoMapper & Unity configuration
AutoMapperConfig.RegisterMaps(Mapper.Configuration, DependencyResolverMock);
UnityConfig.RegisterTypes(TestScopeContainer);
//Set the DomainId
TestId = Guid.NewGuid();
TestDocument = BuildDocument(TestId);
// get the real object
DocumentStoreDbContext = TestScopeContainer.Resolve<IDocumentDbContext>();
InstanceUnderTest = new DocumentRepository(DocumentStoreDbContext);
}
public static Web.Service.DocumentStore.Domain.Document BuildDocument(Guid documentId)
{
// Invoke GetBytes method.
byte[] array = Encoding.ASCII.GetBytes("Byte Repository Test");
return Builder<Web.Service.DocumentStore.Domain.Document>
.CreateNew()
.With(t => t.Id = documentId)
.With(t => t.Data = array)
.Build();
}
When it gets to the DocumentStoreDbContext line, there is no compilation error but i get a run-time error saying that the object name is invalid:
After doing some research this error appears to be because the database/table doesn't exist, however I can see that it does exist:
What am I doing wrong and how do I fix it?
InnerException displays the table name as DocumentStore.Documents, but your SSMS screenshot shows dbo.Documents.
Could this be the cause?

Convert System.Data.Entity.DynamicProxies to (non proxy) class in C#

I am getting some data from the database and storing this in a global variable as shown:
//Global Variable
public static List<stuff> Stuff;
using (var context = new StuffContext())
{
stuff = new List<stuff>();
stuff = (from r in context.Stuff
select r).ToList();
}
The problem I am having is that the context closes and when I wish to access some of the data stored in the global variable, I cannot.
The data is of System.Data.Entity.DynamicProxies.Stuff instead of Application.Model.Stuff which means I then receive this error when I try to do something with the data:
"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
My question is how can I, using the above code as an example, convert / cast to the type that I want so that I can use the data else where in my application?
Edit: Quick screen grab of the error:
The Solution was due to lazy loading after all.
I had to tell the query to grab everything so that when the context closes I still had access to the data.
This is the change I had to make:
public static List<stuff> Stuff;
using (var context = new StuffContext())
{
stuff = new List<stuff>();
stuff = (from r in context.Stuff
.Include(s => s.MoreStuff).Include(s => s.EvenMoreStuff)
select r).ToList();
}
Try to Disable ProxyCreationEnabled In Your Project BbContext constructor As Follow:
Configuration.ProxyCreationEnabled = false;

Is it possible to retrieve a MetadataWorkspace without having a connection to a database?

I am writing a test library that needs to traverse the Entity Framework MetadataWorkspace for a given DbContext type. However, as this is a test library I would rather not have a connection to the database - it introduces dependencies that may not be available from the test environment.
When I try to get a reference to the MetadataWorkspace like so:
var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
I get a SqlException:
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: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
Is it possible to do what I want without a connection string?
Yes you can do this by feeding context a dummy connection string. Note that usually when you call parameterless constructor of DbContext, it will look for connection string with the name of your context class in app.config file of main application. If that is the case and you cannot change this behavior (like you don't own the source code of context in question) - you will have to update app.config with that dummy conneciton string (can be done in runtime too). If you can call DbContext constructor with connection string, then:
var cs = String.Format("metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string=\"\"", "TestModel");
using (var ctx = new TestDBEntities(cs)) {
var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace;
// no throw here
Console.WriteLine(metadata);
}
So you providing only parameters important to obtain metadata workspace, and providing empty connection string.
UPDATE: after more thought, you don't need to use such hacks and instantiate context at all.
public static MetadataWorkspace GetMetadataWorkspaceOf<T>(string modelName) where T:DbContext {
return new MetadataWorkspace(new[] { $"res://*/{modelName}.csdl", $"res://*/{modelName}.ssdl", $"res://*/{modelName}.msl" }, new[] {typeof(T).Assembly});
}
Here you just use constructor of MetadataWorkspace class directly, passing it paths to target metadata elements and also assembly to inspect. Note that this method makes some assumptions: that metadata artifacts are embedded into resources (usually they are, but can be external, or embedded under another paths) and that everything needed is in the same assembly as Context class itself (you might in theory have context in one assembly and entity classes in another, or something). But I hope you get the idea.
UPDATE2: to get metadata workspace of code-first model is somewhat more complicated, because edmx file for that model is generated at runtime. Where and how it is generated is implementation detail. However, you can still get metadata workspace with some efforts:
public static MetadataWorkspace GetMetadataWorkspaceOfCodeFirst<T>() where T : DbContext {
// require constructor which accepts connection string
var constructor = typeof (T).GetConstructor(new[] {typeof (string)});
if (constructor == null)
throw new Exception("Constructor with one string argument is required.");
// pass dummy connection string to it. You cannot pass empty one, so use some parameters there
var ctx = (DbContext) constructor.Invoke(new object[] {"App=EntityFramework"});
try {
var ms = new MemoryStream();
var writer = new XmlTextWriter(ms, Encoding.UTF8);
// here is first catch - generate edmx file yourself and save to xml document
EdmxWriter.WriteEdmx(ctx, writer);
ms.Seek(0, SeekOrigin.Begin);
var rawEdmx = XDocument.Load(ms);
// now we are crude-parsing edmx to get to the elements we need
var runtime = rawEdmx.Root.Elements().First(c => c.Name.LocalName == "Runtime");
var cModel = runtime.Elements().First(c => c.Name.LocalName == "ConceptualModels").Elements().First();
var sModel = runtime.Elements().First(c => c.Name.LocalName == "StorageModels").Elements().First();
var mModel = runtime.Elements().First(c => c.Name.LocalName == "Mappings").Elements().First();
// now we build a list of stuff needed for constructor of MetadataWorkspace
var cItems = new EdmItemCollection(new[] {XmlReader.Create(new StringReader(cModel.ToString()))});
var sItems = new StoreItemCollection(new[] {XmlReader.Create(new StringReader(sModel.ToString()))});
var mItems = new StorageMappingItemCollection(cItems, sItems, new[] {XmlReader.Create(new StringReader(mModel.ToString()))});
// and done
return new MetadataWorkspace(() => cItems, () => sItems, () => mItems);
}
finally {
ctx.Dispose();
}
}
The solution proposed by Evk did not work for me as EdmxWriter.WriteEdmx would eventually connect to the database.
Here is how I solved this:
var dbContextType = typeof(MyDbContext);
var dbContextInfo = new DbContextInfo(dbContextType, new DbProviderInfo(providerInvariantName: "System.Data.SqlClient", providerManifestToken: "2008"));
using (var context = dbContextInfo.CreateInstance() ?? throw new Exception($"Failed to create an instance of {dbContextType}. Does it have a default constructor?"))
{
var workspace = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
// ... use the workspace ...
}
By creating the context this way, Entity Framework does not try to connect to the database when accessing the ObjectContext property.
Note that your DbContext class must have a default constructor for this solution to work.

How to access entity's properties outside context using Entity Framework?

I'm new to Entity Framework (working mostly with NHibernate with ActiveRecord before) and I'm stuck with something, that I think should be easy...
I have a User Entity, and created partial User class so I can add some methods (like with NHibernate). I added GetByID to make getting user easier:
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Where(qq => qq.UserID == userID).Single();
}
}
Now in the same class I want to log moment of logging in, and I try to do:
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
The problem is I can't access user.LoginLogs because user's context is already disposed... Most likely I'm missing something obvious here, but creating always full queries like:
context.Users.Where(qq => qq.UserID == userID).Single().LoginLogs.Add(log);
doesn't seem like a good option...
I've read about Repository pattern but I think it's too big gun for such task. Please explain me what am I doing wrong. Thanks in advance!
EDIT
To picture what I'd like to do:
//somewhere in business logic
var user = User.GetByID(userID);
var posts = user.GetAllPostsForThisMonth();
foreach(var post in posts)
{
Console.WriteLine(post.Answers.Count);
}
Normally I'm not allowed to do this because I can't get post.Answers without context...
You are closing the object context and then trying to add a log to the user that is detached. You need to attach the user so the objectContext know what has been changed or added.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = context.User.Where(p=>p.UserID == userID); //<= The Context now knows about the User, and can track changes.
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
Update
You can also attach the object.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.User.Attach(user);
context.SaveChanges();
}
}
Update
var getFirstLogin = from p in User.GetUserById(userId)
select p.LoginLogs.FirstOrDefault();
NB if LoginLogs is a different table you will need to use Include.
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Include("LoginLogs").Where(qq => qq.UserID == userID).FirstOrDefault();
}
}
If you are open to using stored procedures (and they work nicely with EF), you can return the user object and simultaneously add to the log table with a single call to the database.
I used to do everything with SP's in my pre-EF/ORM days, when I went to EF I tried very hard to avoid using stored procedures to avoid falling back into my old habits, but now I have found that the selective use of stored procedures you can have the benefits of both -the EF way of doing things, and the super functionality/performance that a well written SP can provide.

How to relate objects from multiple contexts using the Entity Framework

I am very new to the entity framework, so please bear with me...
How can I relate two objects from different contexts together?
The example below throws the following exception:
System.InvalidOperationException: The
relationship between the two objects
cannot be defined because they are
attached to different ObjectContext
objects.
void MyFunction()
{
using (TCPSEntities model = new TCPSEntities())
{
EmployeeRoles er = model.EmployeeRoles.First(p=>p.EmployeeId == 123);
er.Roles = GetDefaultRole();
model.SaveChanges();
}
}
private static Roles GetDefaultRole()
{
Roles r = null;
using (TCPSEntities model = new TCPSEntities())
{
r = model.Roles.First(p => p.RoleId == 1);
}
return r;
}
Using one context is not an option because we are using the EF in an ASP.NET application.
You will have to use the same context (you can pass the context to the getdefaultrole method) or rethink the relationships and extend the entity.
EDIT: Wanted to add this was for the example provided, using asp.net will require you to fully think out your context and relationship designs.
You could simply pass the context.. IE:
void MyFunction()
{
using (TCPSEntities model = new TCPSEntities())
{
EmployeeRoles er = model.EmployeeRoles.First(p=>p.EmployeeId == 123);
er.Roles = GetDefaultRole(model);
model.SaveChanges();
}
}
private static Roles GetDefaultRole(TCPSEntities model)
{
Roles r = null;
r = model.Roles.First(p => p.RoleId == 1);
return r;
}
Another approach that you could use here is to detach objects from one context, and then attach them to another context. That's a bit of a hack, and it may not work in your situation, but it might be an option.
public void GuestUserTest()
{
SlideLincEntities ctx1 = new SlideLincEntities();
GuestUser user = GuestUser.CreateGuestUser();
user.UserName = "Something";
ctx1.AddToUser(user);
ctx1.SaveChanges();
SlideLincEntities ctx2 = new SlideLincEntities();
ctx1.Detach(user);
user.UserName = "Something Else";
ctx2.Attach(user);
ctx2.SaveChanges();
}
Yep - working across 2 or more contexts is not supported in V1 of Entity Framework.
Just in case you haven't already found it, there is a good faq on EF at http://blogs.msdn.com/dsimmons/pages/entity-framework-faq.aspx
From what I understand, you want to instantiate your model (via the "new XXXXEntities()" bit) as rarely as possible. According to MS (http://msdn.microsoft.com/en-us/library/cc853327.aspx), that's a pretty substantial performance hit. So wrapping it in a using() structure isn't a good idea. What I've done in my projects is to access it through a static method that always provides the same instance of the context:
private static PledgeManagerEntities pledgesEntities;
public static PledgeManagerEntities PledgeManagerEntities
{
get
{
if (pledgesEntities == null)
{
pledgesEntities = new PledgeManagerEntities();
}
return pledgesEntities;
}
set { pledgesEntities = value; }
}
And then I retrieve it like so:
private PledgeManagerEntities entities = Data.PledgeManagerEntities;

Categories

Resources