A one time error breaks subsequent usage of Entity framework - ef-code-first

We have a problem with entity framework. For example if we do:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
and then we try to delete an entity that has mapped child entities who depend on it, it is logical that we get an error. (Cannot delete parent when there are children in database that depend on it).
Afterwards, using a new context instance, doing a 'ParentEntity.ChildEntities.ToList()' there is still a problem!
A workaround is to restart the app pool, and the problem goes away.
We are using Autofac and the lifecycle of the context is set (and confirmed) to per HttpRequest, so the error persists somewhere else. Any idea what can be done so as to avoid these errors?
Our guess is that the objectcontext is persistent somewhere else, and it stores the state of the child entities as "EntityState.Deleted" so this conflicts with the actual data received from the database on subsequent calls.
Update: Seems like a closer examination of the stack reveals that there is a lazy internal context:
[DbUpdateException: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.]
System.Data.Entity.Internal.InternalContext.SaveChanges() +200
System.Data.Entity.Internal.LazyInternalContext.SaveChanges() +33
System.Data.Entity.DbContext.SaveChanges() +20
Maybe if I were to somehow disable LazyInternalContext? Can this be done?

If you don't want to get the exceptions and keep the database in a valid state by your self for some reason you can do so by stopping validation:
context.Configuration.ValidateOnSaveEnabled = false; // you can put this in the constructor of your context;
context.SaveChanges();

Related

Entity Framework Core Scaffold - Dynamic Schema Name

I'm having an issue at the moment where, we have a database which was already created, so used ef scaffold to create a model of it - the schema the model was created against is called "xxxx-dev".
Now, this has been fine, but in preparation to go live, I created a new DB server and provisioned the database to be called "xxxx-live". Switched the connection string, and attempted a query against it, and got an error.
It seems that scaffolding has hard-coded the schema name into every table in the OnModelCreating call, for example:
modelBuilder.Entity<xxxx>(entity =>
{
...
entity.ToTable("xxxx", "xxxx-dev");
...
});
This is a bit of an issue as going forward, we might have multi-tenant sites based on the same database, and obviously the query overriding the connection string every query isn't a great experience.
Is there anyway to configure the schema name, either in the Scaffold, or at runtime? I've done a bit of searching around and can't seem to see a solution.
Thanks,

Determine if Cosmos DB NotFound due to missing collection vs. document

Is there a way to programmatically determine from a DocumentClientException where StatusCode == HttpStatusCode.NotFound whether it was the document, the collection, or the database that was not found?
I'm trying to figure out whether I can implement on-demand collection provisioning and only call DocumentClient.CreateDocumentCollectionIfNotExistsAsync when I need to. I'm trying to avoid calling it before making every request (presumably this adds an extra network roundtrip to every request). Likewise, I'm trying to avoid calling it on error recovery when I know it won't help.
From experimentation with the local emulator, the only field I see varying in these three cases is DocumentClientException.Error.Message, and only when the database cannot be found. I generally try to avoid exception dispatching based on human-readable messages.
Wrong database name:
StatusCode: HttpStatusCode.NotFound
Error.Message: {\"Errors\":[\"Owner resource does not exist\"]}...
Correct database name, wrong collection name:
StatusCode: HttpStatusCode.NotFound
Error.Message: {\"Errors\":[\"Resource Not Found\"]}...
Correct database name, correct collection name, incorrect document ID:
StatusCode: HttpStatusCode.NotFound
Error.Message: {\"Errors\":[\"Resource Not Found\"]}...
I'm planning to use a database with its own offer. Since collections inside a database with its own offer are cheap, I'm trying to see whether I can segregate each tenant in my multi-tenant application into its own collection. Each tenant ends up having a different indexing and default TTL policy. The set of collections is not fixed and changes dynamically during runtime as new tenants sign up. I cannot predict when I will need to add a new collection. There's no new tenant notification: I just get a request that I need to handle by creating a document in a possibly non-existent collection. There's a process to garbage collect unused collections.
I'm using the NuGet package Microsoft.Azure.DocumentDB.Core Version 1.9.1 in a .NET Core 2.1 app targeting a SQL API Cosmos DB instance.
If you look at the Message property in detail, you should see following strings that informs whether 404 Not Found response was generated due to Document vs Collection.
ResourceType: Document
ResourceType: Collection
It's not ideal but you can try to regex this information out of error message.

Query regarding database connectivity in db4o

I'm creating a db4o object (namely Customer.yap) and if it is already created i just insert new objects into the existing object (namely Customer.yap) .
For both these operations i'm just using:
IObjectContainer db1 = Db4oEmbedded.OpenFile(Db4oEmbedded.NewConfiguration(),#"C:\Users\admin\Desktop\Db4oObjectFiles\Components.yap");
try
{
db1.Store(comp1);
}
finally
{
db1.Close();
}
Am i doing it right or is there a separate command to check if the object exists and then insert values or can i use the same code for both the operations meaning db4o automatically checks if the object exists at the specified location if it exists it inserts the objects other wise it creates the object at the specified location and then insert the object.
Please help me
Thanks in anticipation
PS: i'm doing this in the context of web application in asp.net and then there is this thought that is always lurking in my mind. should n't i be using the remote connection rather than storing it in actual physical location, but i could n't just figure it how does someone create and store objects in the context of remote connection. i don't know which parameters to specify namely host, port username and password and i even don't know how does some one create database connection what r the statements one should write in the program to connect to this remote object file.
Please please help me and guide me.
A big thanks to anyone in anticipation
db4o automatically updates the object instead of inserting it but there's a catch: you'll have to keep your object container open. db4o works with a local cache that keeps track of stored objects, but once you call close() on the object container that local cash is gone. If you store a previously persisted after a close() on the object container you'll get a duplicate object (db4o thinks it's a new one). If you really have to close the object container and want to update an object you'll have to query for it on db4o, then update, then call store (and then you can close()).
With regards to how to connect to a remote db4o server please see:
http://developer.db4o.com/Documentation/Reference/db4o-7.12/java/reference/Content/client-server/networked.htm
Best! (good luck!)

Recycle windows workflow after changes on workflow activity

I used WWF on my web project, on this project I have several workflows and visitor will fill forms and then form will post to technical people to do their job and some other state ...
When I change workflow and create new activity or state , when run ( continue ) all workflows that persist on db before changes , will throw errors.
Server was unable to process request. ---> System.InvalidOperationException: Workflow with id "82b0cb6c-d6b7-43cd-9071-04a1078954ec" not found in state persistence store.
at System.Workflow.Runtime.Hosting.PersistenceDBAccessor.RetrieveInstanceState(Guid instanceStateId, Guid ownerId, DateTime timeout)
at System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService.LoadWorkflowInstanceState(Guid id)
at System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(Guid instanceId, CreationContext context, WorkflowExecutor executor, WorkflowInstance workflowInstance)
at System.Workflow.Runtime.WorkflowRuntime.Load(Guid key, CreationContext context, WorkflowInstance workflowInstance)
at System.Workflow.Runtime.WorkflowRuntime.GetWorkflow(Guid instanceId)
at System.Workflow.Activities.WorkflowWebService.Invoke(Type interfaceType, String methodName, Boolean isActivation, Object[] parameters)
how can I recycle old workflows after changes?
Thanks
Your error looks pretty specific there. The workflow with your particular GUID doesn't exist.
Changing a workflow definition does not change existing workflows. They will continue to execute their predetermined definitions unless you initiate an actual change process on them. You'll want to dig into Dynamic Workflow Updates if this is what you want to accomplish.

NHibernate thread safety with session

I've been using NHibernate for a while now and have found from time to time that if I try to request two pages simultaniously (or as close as I can) it will occasionally error. So I assumed that it was because my Session management was not thread safe.
I thought it was my class so I tried to use a different method from this blog post http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/ however I still get the same issues. The actual error I am getting is:
Server Error in '/AvvioCMS' Application.
failed to lazily initialize a collection, no session or session was closed
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: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
Either that or no datareader is open, but this is the main culprit.
I've placed my session management class below, can anyone spot why I may be having these issues?
public interface IUnitOfWorkDataStore
{
object this[string key] { get; set; }
}
public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies)
{
if (storage == null)
throw new Exception("storage mechanism was null but must be provided");
Configuration cfg = ConfigureNHibernate(string.Empty);
foreach (Assembly assembly in assemblies)
{
cfg.AddMappingsFromAssembly(assembly);
}
SessionFactory = cfg.BuildSessionFactory();
ContextDataStore = storage;
return cfg;
}
public static ISessionFactory SessionFactory { get; set; }
public static ISession StoredSession
{
get
{
return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession];
}
set
{
ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value;
}
}
public const string CDS_NHibernateSession = "NHibernateSession";
public const string CDS_IDbConnection = "IDbConnection";
public static IUnitOfWorkDataStore ContextDataStore { get; set; }
private static object locker = new object();
public static ISession Current
{
get
{
ISession session = StoredSession;
if (session == null)
{
lock (locker)
{
if (DBConnection != null)
session = SessionFactory.OpenSession(DBConnection);
else
session = SessionFactory.OpenSession();
StoredSession = session;
}
}
return session;
}
set
{
StoredSession = value;
}
}
public static IDbConnection DBConnection
{
get
{
return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection];
}
set
{
ContextDataStore[NHibernateSession.CDS_IDbConnection] = value;
}
}
}
And the actual store I am using is this:
public class HttpContextDataStore : IUnitOfWorkDataStore
{
public object this[string key]
{
get { return HttpContext.Current.Items[key]; }
set { HttpContext.Current.Items[key] = value; }
}
}
I initialize the SessionFactory on Application_Start up with:
NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] {
typeof(MappedClass).Assembly});
Update
Thanks for your advice. I have tried a few different things to try and simplify the code but I am still running into the same issues and I may have an idea why.
I create the session per request as and when it is needed but in my global.asax I am disposing of the session on Application_EndRequest. However I'm finding the Application_EndRequest is being fired more than once while I am in debug at the end of loading a page. I thought that the event is only suppose to fire once at the very end of the request but if it isn't and some other items are trying to use the Session (which is what the error is complaining about) for whatever weird reason that could be my problem and the Session is still thread safe it is just being disposed of to early.
Anyone got any ideas? I did a google and saw that the VS development server does cause issues like that but I am running it through IIS.
While I haven't seen your entire codebase or the the problem you're trying to solve, a rethinking of how you are using NHibernate might be in order. From the documentation:
You should observe the following
practices when creating NHibernate
Sessions:
Never create more than one concurrent
ISession or ITransaction instance per
database connection.
Be extremely careful when creating
more than one ISession per database
per transaction. The ISession itself
keeps track of updates made to loaded
objects, so a different ISession might
see stale data.
The ISession is not threadsafe! Never
access the same ISession in two
concurrent threads. An ISession is
usually only a single unit-of-work!
That last bit is the most relevant (and important in the case of a multithreaded environment) to what I'm saying. An ISession should be used once for a small atomic operation and then disposed. Also from the documentation:
An ISessionFactory is an
expensive-to-create, threadsafe object
intended to be shared by all
application threads. An ISession is an
inexpensive, non-threadsafe object
that should be used once, for a single
business process, and then discarded.
Combining those two ideas, instead of storing the ISession itself, store the session factory since that is the "big" object. You can then employ something like SessionManager.GetSession() as a wrapper to retrieve the factory from the session store and instantiate a session and use it for one operation.
The problem is also less obvious in the context of an ASP.NET application. You're statically scoping the ISession object which means it's shared across the AppDomain. If two different Page requests are created within that AppDomain's lifetime and are executed simultaneously, you now have two Pages (different threads) touching the same ISession which is not safe.
Basically, instead of trying to keep a session around for as long as possible, try to get rid of them as soon as possible and see if you have better results.
EDIT:
Ok, I can see where you're trying to go with this. It sounds like you're trying to implement the Open Session In View pattern, and there a couple different routes you can take on that:
If adding another framework is not an issue, look into something like Spring.NET. It's modular so you don't have to use the whole thing, you could just use the NHibernate helper module. It supports the open session in view pattern. Documentation here (heading 21.2.10. "Web Session Management").
If you'd rather roll your own, check out this codeproject posting by Bill McCafferty: "NHibernate Best Practices". Towards the end he describes implementing the pattern through a custom IHttpModule. I've also seen posts around the Internet for implementing the pattern without an IHttpModule, but that might be what you've been trying.
My usual pattern (and maybe you've already skipped ahead here) is use a framework first. It removes lots of headaches. If it's too slow or doesn't fit my needs then I try to tweak the configuration or customize it. Only after that do I try to roll my own, but YMMV. :)
I can't be certain (as I'm a Java Hibernate guy) in NHibernate but in hibernate Session objects are not thread safe by design. You should open and close a session and never allow it out of the scope of the current thread.
I'm sure that patterns such as 'Open session view' have been implemented in .Net somewhere.
The other interesting issue is when you put a hibernate entity in the session. The problem here is that the session that it is attached to will be closed (or should be) on the request finishing. You have to reattach the entity to the new (hibernate) session if you wish to navigate any non loaded associations. This in it's self causes a new issue if two requests try to do this at the same time as something will blow up if you try to attach an entity to two sessions.
Hope this helps.
Gareth
The problem ended up being that my library for inversion of control was not managing the objects being created in HTTP context correctly so I was getting references for objects that should of not been available to that context. This was using Ninject 1.0, once I updated to Ninject 2.0 (beta) the problem was resolved.

Resources