I have the following seemingly simple scenario, however I'm still pretty new to NHibernate.
When trying to load the following model for an Edit action on my Controller:
Controller's Edit Action:
public ActionResult Edit(Guid id)
{
return View(_repository.GetById(id));
}
Repository:
public SomeModel GetById(Guid id)
{
using (ISession session = NHibernateSessionManager.Instance.GetSession())
return session.Get<SomeModel >(id);
}
Model:
public class SomeModel
{
public virtual string Content { get; set; }
public virtual IList<SomeOtherModel> SomeOtherModel { get; set; }
}
I get the following error:
-failed to lazily initialize a collection of role: SomeOtherModel, no session or session was closed
What am I missing here?
The problem is that you create and also close the session in you models GetById method. (the using statement closes the session) The session must be available during the whole business transaction.
There are several ways to achieve this. You can configure NHibernate to use the session factories GetCurrentSession method. See this on nhibernate.info or this post on Code Project.
public SomeModel GetById(Guid id)
{
// no using keyword here, take the session from the manager which
// manages it as configured
ISession session = NHibernateSessionManager.Instance.GetSession();
return session.Get<SomeModel >(id);
}
I don't use this. I wrote my own transaction service which allows the following:
using (TransactionService.CreateTransactionScope())
{
// same session is used by any repository
var entity = xyRepository.Get(id);
// session still there and allows lazy loading
entity.Roles.Add(new Role());
// all changes made in memory a flushed to the db
TransactionService.Commit();
}
However you implement it, sessions and transactions should live as long as a business transaction (or system function). Unless you can't rely on transaction isolation nor rollback the whole thing.
You need to eagerly load the SomeOtherModel collection if you intend to use it before closing the session:
using (ISession session = NHibernateSessionManager.Instance.GetSession())
{
return session
.CreateCriteria<SomeModel>()
.CreateCriteria("SomeOtherModel", JoinType.LeftOuterJoin)
.Add(Restrictions.Eq(Projections.Id(), id))
.UniqueResult<SomeModel>();
}
By default FluentNHibernate uses lazy loading for collection mappings. Another option is to modify this default behavior in your mapping:
HasMany(x => x.SomeOtherModel)
.KeyColumns.Add("key_id").AsBag().Not.LazyLoad();
Note that if you do this SomeOtherModel will be eagerly loaded (using an outer join) every time you load the parent entity which might not be want you want. In general I prefer to always leave the default lazy loading at the mapping level and tune my queries depending on the situation.
"If we want to access the order line items (after the session has been closed) we get an exception. Since the session is closed NHibernate cannot lazily load the order line items for us. We can show this behavior with the following test method"
[Test]
[ExpectedException(typeof(LazyInitializationException))]
public void Accessing_customer_of_order_after_session_is_closed_throws()
{
Order fromDb;
using (ISession session = SessionFactory.OpenSession())
fromDb = session.Get<Order>(_order.Id);
// trying to access the Customer of the order, will throw exception
// Note: at this point the session is already closed
string name = fromDb.Customer.CompanyName;
}
"Eagerly loading with the NHibernateUtil class If you know you need have access to related objects of the order entity you can use the NHibernateUtil class to initialize the related objects (that is: to fetch them from the database)."
[Test]
public void Can_initialize_customer_of_order_with_nhibernate_util()
{
Order fromDb;
using (ISession session = SessionFactory.OpenSession())
{
fromDb = session.Get<Order>(_order.Id);
NHibernateUtil.Initialize(fromDb.Customer);
}
Assert.IsTrue(NHibernateUtil.IsInitialized(fromDb.Customer));
Assert.IsFalse(NHibernateUtil.IsInitialized(fromDb.OrderLines));
}
Reference: http://nhibernate.info/doc/howto/various/lazy-loading-eager-loading.html
Related
Are objects that are referenced, not created, within a factory implementation disposed by the container? See code below:
services.AddTransient(c => OwinContext.ServiceObject);
Will ServiceObject, which implements IDisposable, be disposed by the container considering it isn't created (i.e. new ServiceObject)?
ServiceObject is currently registered as Scoped, but we are getting ObjectDisposedException on the rare occasion. I'm guessing it's getting disposed within OWIN sometimes before our services are able to use it, which is why I was hoping of making it Transient but I'm worried the container will dispose of it more frequently.
Disposable transient registrations are tracked by the container and disposed when their scope ends.
The Microsoft documentation is not always clear about this, as this documentation seems to suggest that "The framework does not dispose of the services automatically" that are "not created by the service container." Although the documentation is not incorrect, as it primarily talks about the registration of instances through the AddSingleton<T>(T instance) extension method — it is misleading because it doesn't hold for:
AddSingleton<T>(Func<IServiceProvider, T>),
AddScoped<T>(Func<IServiceProvider, T>), and
AddTransient<T>(Func<IServiceProvider, T>).
This statement can be easily verified using the following program:
using Microsoft.Extensions.DependencyInjection;
var disposable = new FakeDisposable();
var services = new ServiceCollection();
services.AddTransient(c => disposable);
var provider = services.BuildServiceProvider(validateScopes: true);
using (var scope = provider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
}
public class FakeDisposable : IDisposable
{
public void Dispose() => Console.WriteLine("Disposed");
}
Output:
Disposed
Conclusion: Yes, transient registrations for disposable objects are disposed of by the container.
There will be little difference between making this registration Transient or Scoped. In both cases the object will get disposed when the scope ends.
In the case of a Transient registration, though, you'll start to see the disposable get disposed of multiple times in case it gets injected multiple times. For instance:
using (var scope = provider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
}
Output:
Disposed
Disposed
Disposed
From reliability, however, it's better to stick with a Scoped registration, instead of Transient. This is because MS.DI will prevent Scoped registrations from being injected into Singleton consumers (in case the Service Provider is created by calling BuildServiceProvider(validateScopes: true)). In case your ServiceContext would get injected into a Singleton, it causes it to become a Captive Dependency and keep referenced (and likely used) by that Singleton, long after it got disposed of.
The most likely reason you are getting those ObjectDisposedExceptions is because Owin tries to use the ServiceContext after your (web request) scope is disposed.
The ServiceContext object is likely being controlled and disposed of by OWIN, which doesn't make it a good candidate to be disposed of by the container. But here's the problem: MS.DI will always try to dispose of Transient and Scoped registrations and the only way to prevent this from happening is to not register your ServiceContext.
The solution, therefore, is to wrap it in a "provider" object of some sort. For instance:
// New abstraction
public interface IServiceObjectProvider
{
object ServiceObject { get; }
}
// Implementation part of your Composition Root (see: https://mng.bz/K1qZ)
public class AmbientOwinServiceObjectProvider : IServiceObjectProvider
{
public object ServiceObject => OwinContext.ServiceObject;
}
// Registration:
services.AddScoped<IServiceObjectProvider, AmbientOwinServiceObjectProvider>();
// Usage:
public class MyController : Controller
{
private readonly IServiceObjectProvider provider;
public MyController(IServiceObjectProvider provider)
{
// Only store the dependency here: don't use it,
// see: https://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/
this.provider = provider;
}
public string Index()
{
var so = this.provider.ServiceObject;
// Do something with the Service object
}
}
I googled a bit and searched this forum before posting this, since I presumed it had been beaten to death - but since I didn't see any results that seemed clearly asking this, I figured I'd give it a shot. There's a pretty high chance it's been answered before, but I didn't stumble upon a clear page about it.
When using dependency injection, which is considered the better practice? Injecting the entire IDocumentStore and then spawning a session from it as needed, or injecting the appropriate IDocumentSession or IAsyncDocumentSession?
In the past, I've injected IAsyncDocumentSession everywhere - but it's come up that I actually need to use a non async session in a few places. This got me to thinking if I was just approaching injecting Raven wrong altogether.
So, using the IDocumentStore might be like ...
public AsHandler(IDocumentStore store) { RavenStore = store; }
private IDocumentStore RavenStore { get; set; }
public async Task Handle() {
using(var session = RavenStore.OpenAsyncSession()) {
... // do stuff with an async session
}
}
But then the more specific session usecases would appear such as ...
public AsHandler(IAsyncDocumentSession session) { RavenSession = session; }
private IAsyncDocumentSession RavenSession { get; set; }
public async Task Handle() {
// do stuff with an async session
}
or respectively ...
public AsHandler(IDocumentSession session) { RavenSession = session; }
private IDocumentSession RavenSession { get; set; }
public async Task Handle() {
// do stuff with a non-async session
}
Is there even any difference other than preference? My initial thought is that using the IDocumentSession and IAsyncDocumentSession is better lifecycle management, but I could be wrong.
I am using .NET Core 2.0.3 with StructureMap with Raven DB 4.0 (40023) specifically, but I would posit that this could apply to any configuration and any version.
Not sure this has changed with 4.0 but so far the creation of the DocumentStore was considered a rather expensive/heavy operation and therefore the suggested approach is to create it only once per application (singleton; for futher details please see RavenDb Documentation).
Sessions on the other hand are rather cheap to create and therefore can be created as needed.
You could still inject both objects (store and session) with DI and just use different lifecycles (singleton vs. transient).
Of course you can also setup DI to provide either the sync- or the asnyc-version of the session as needed.
I am using Castle ActiveRecord in my Asp.net / MVC 2 / Multi-tenancy application with SQL Server as my backend.
For every user logging in, the app loads the corresponding DB, dynamically at run time like below:
IDictionary<string, string> properties = new Dictionary<string, string>();
properties.Add("connection.driver_class", "NHibernate.Driver.SqlClientDriver");
properties.Add("dialect", "NHibernate.Dialect.MsSql2005Dialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("proxyfactory.factory_class", "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle");
properties.Add("connection.connection_string", strDBConnection);
InPlaceConfigurationSource source = new InPlaceConfigurationSource();
source.Add(typeof(ActiveRecordBase), properties);
ActiveRecordStarter.Initialize(new System.Reflection.Assembly[] { asm1 }, source);
The strDBConnection string comes from another small database that holds the user info, corresponding DB, etc.
Scenario:
When a user logs in, his DB gets loaded, he can do his CRUD jobs -- No Probs !
Another user logs in (from another remote machine) his DB gets loaded -- No Probs !
Now, when the first user reads from DB, he sees new data from the second user's DB
My little understanding for this behavious is : ActiveRecordStarter is a Static object.
Could someone help me with a solution for this situation ?
The expected behaviour:
each user should access his own DB only, securely, in parallel / at the same time.
Thanks a lot !
ActiveRecordStarter.Initialize should only be called once in your app (in Application_Start in Global.asax).
To achieve what you want, create a class that inherits from NHibernate.Connection.DriverConnectionProvider:
public class MyCustomConnectionProvider : DriverConnectionProvider
{
protected override string GetNamedConnectionString(IDictionary<string, string> settings)
{
return string.Empty;
}
public override IDbConnection GetConnection()
{
// Get your connection here, based on the request
// You can use HttpContext.Current to get information about the current request
var conn = Driver.CreateConnection();
conn.ConnectionString = ... // Retrieve the connection string here;
conn.Open();
return conn;
}
}
Then set the connection.provider property to the name of your class:
properties.Add("connection.provider", "MyCompany.Domain.MyCustomConnectionProvider, MyCompany.AssemblyName");
I have a simple asp.net MVC4 / EF 4.1 project created with VS 2011, with a layer for my domain model and one for my database that contains the DbContext. I have one basic domain class called Batch and a BatchController with the standard CRUD functionality using Index / Create / Edit actions. I add two default records with the overridden Seed method. All this works fine I can add / edit / delete records using the out of the box MVC template:
public class BatchController : Controller
{
private readonly MyContext _context = new MyContext();
public ActionResult Index()
{
return View(_context.Batches.ToList());
}
[HttpPost]
public ActionResult Create(Batch batch)
{
if (ModelState.IsValid)
{
this._context.Batches.Add(batch);
this._context.SaveChanges();
return RedirectToAction("Index");
}
return View(batch);
}
}
I added a new MVC4 Web api project to the solution with the intention of exposing the domain object so the data can be retrieved via json. This uses an api controller that I've called BatchesController, and I added a reference to my domain and database layers. I have two Get() methods, one to return all Batches and one to return a single batch given an id. I'm using IIS Express to host the main MVC app and the Web api. To retrieve all the Batches I run this in a browser:
http://localhost:46395/api/batches
Here's my Web api Controller :
public class BatchesController : ApiController
{
private readonly MyContext _context;
public BatchesController()
{
_context = new MyContext();
}
// GET /api/batches
public IEnumerable<Batch> Get()
{
var batches = _context.Batches.ToList();
if (batches == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
return batches;
}
// GET /api/batches/5
public Batch Get(int id)
{
var batch = _context.Batches.Find(id);
if (batch == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
return batch;
}
}
My problem is that when I add a new record and try to retrieve it via a browser, only the existing records aded with the Seed method are returned - I can't get any newly added record to be returned. The DbContext seems to be caching the initial records and not going to the database to get the latest...how do I return newly added records?
Just to clear out the obvious, you have surely rewired to Web API project to point to the same database, right? Because by default Web API will attach its own SQL Compact DB. Meaning that you could effectively be using 2 separate databases
There is an answer, which It doesn't solve my problem:
http://www.strathweb.com/2012/03/serializing-entity-framework-objects-to-json-in-asp-net-web-api/
Also, there is a same question at here:
http://forums.asp.net/t/1814377.aspx/1?Web+api+not+returning+records+from+EF+4+1+DbContext
and I find this useful:
ASP.Net Web API showing correctly in VS but giving HTTP500
BUT THE POINT IS:
You can not send the proxy object to webapi serializer. So it should be project to a new dynamic class or a predefined class which there is no virtual (or maybe IList, ICollection,...).
// GET api/ProfileGame
public dynamic GetProfileGames()
{
return db.ProfileGames.Select(pg => new
{
...
}).AsEnumerable();
}
I use Entity Framework 4 and ASP.NET MVC 3. I made a custom membership provider and use Ninject to inject an EFAccountRepository into it (Bound IAccountRepository to EFAccountRepository).
This account repository has an ObjectContext injected into it. I also use this repository (and others) in my controllers. For this reason when I bound IContext to my ObjectContext, I set the scope to "per request" so the ObjectContext only lives in one request and is shared between the repositories.
I am sometimes get the following error when trying to log in:"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
I wonder how often the membership provider gets instantiated. I injected the repository into the membership provider by marking the repository property with [Inject] and calling Kernel.Inject in the Application_Start function in the global.asax file.
If the provider gets instantiated more than once I would have to inject again I suppose. However, I don't get a null pointer exception, so I don't think that's it.
Update 1
Here's some code:
MyNinjectModule.cs
public override void Load()
{
Bind<IMyContext>().To<MyObjectContext>().InRequestScope();
// put bindings here
Bind<IAccountRepository>().To<EFAccountRepository>
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var kernel = new StandardKernel(new MyNinjectModule());
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(kernel));
kernel.Inject(Membership.Provider);
}
MyMembershipProvider.cs
[Inject]
public IAccountRepository accountRepository { get; set; }
public override bool ValidateUser(string username, string password)
{
// I get the exception here.
return (from a in accountRepository.Accounts
where a.UserName == username
&& a.Password == password
select true).SingleOrDefault();
}
EFAccountRepository.cs
private readonly IMyContext context;
public EFAccountRepository(IMyContext context)
{
this.context = context;
}
public IQueryable<Account> Accounts
{
get { return context.Accounts; }
}
MyObjectContext.cs
public class MyObjectContext : ObjectContext, IMyContext
{
public IObjectSet<Account> Accounts { get; private set; }
public FlorenceObjectContext()
: this("name=DomainModelContainer")
{
}
public FlorenceObjectContext(string connectionString)
: base(connectionString, "DomainModelContainer")
{
Accounts = CreateObjectSet<Account>();
}
}
PS: I'm always open to comments on my code in general ;).
The exception says that you are incorrectly handling disposing of your context. Somewhere you call context.Dispose (or have context in using) but after that you want to use context again which is not possible because context is already disposed. If you are using per request context you must dispose context only once at the end of request processing (when you are sure that no code will use the context).
You didn't specify a scope for your EFAccountRepository binding so it defaults to .InTransientScope(). This means a new instance of the object will be created each time you resolve the IAccountRepository [refer to https://github.com/ninject/ninject/wiki/Object-Scopes ].
Also, transient scope objects
are automatically garbage collected as soon as there are no references to them [Ninject doesn't cache them]
are not automatically disposed by anyone
In contrast, you bound MyObjectContext to IObjectContext .InRequestScope(). This means it will be reused when you are in the same HTTP request handling operation.
Also, a request scope object
won't be garbage collected until your http request is done
might be automatically disposed once the HTTP request is done, if it's IDisposable. [Not sure precisely when, but from other questions I have seen I suspect it depends on the version of Ninject]
Now, ObjectContext is IDisposable, so it seems reasonable to conclude that
an object reference to the IObjectContext exists, and you are using the IObjectContext outside of the HTTP request which it was created in.
Ninject has automatically disposed of it, since the HTTP request has completed.
In order to solve the issue, you need to figure out why your object context object reference is surviving so long, and consider either eliminating the long-livedness... or removing its dependency on short-lived (request-scoped) objects.
[note clearly the question already has an accepted answer, but I think the accepted answer was kind of hard to understand.]