I have a class which loads all of the data I want on screen.
I am loading all the data within a using statement and returning the resultant records in a higher class.
I am able to loop through the objects, but any nested objects are unavailable and I get the error "The function evaluation requires all threads to run." when I try to inspect the objects.
The returned error to the web page is "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
Is there a way in EF6 for me to load all the objects and nested objects and make them available outside of the context?
Using statement will automatically dispose the object.
You can use include while fetching main entities to also fetch the related entities.
https://msdn.microsoft.com/en-us/data/jj574232.aspx
DbContext isn't supposed to be used for a long time. It's better to instantiate context, copy all data that you need from it in to some array/collection and dispose it right after that. Then you can access your data with this array/collection.
Example:
In Controller class
Person[] people = Repo.GetAllPeople();
And in Repository class you have something like:
public People[] GetAllPeople()
{
try
{
MyDbContext cont = new MyDbContext();
return cont.People.ToArray();
}
catch { return null; }
finally { cont.Dispose(); }
}
P.S.
And yes - using statement is nothing else then just :
try
{
...instantiate some_resource that inherits from IDisposable
...do something with this resource
}
finally { some_resource.Dispose(); }
Related
Enclosed below is an example of one of the methods that I created.
Am I correctly implementing EF6? As you can see in my commented code I first tried to create a repository class. I instead scrapped the repository class for this implementation. However I am now getting errors because I am returning an IQueryable object and then closing the dbcontext.
So this led me to the question: Am I implementing EF6 correctly?
I could change the IQueryable to return a List<obj> or I could remove the using (_myContext) statement. I'm just trying to understand the correct way to implement my methods.
public IQueryable<MY_USERS> GetAllUsers()
{
using (_myContext)
{
return _myContext.MY_USERS;
}
//MyRepository<MY_USERS> users = new MyRepository<MY_USERS>(_myContext);
//return users.GetAll();
}
Updated example:
public void DeleteUser(string userName)
{
using (var context = new MyEFConn())
{
using (var transaction = context.Database.BeginTransaction())
{
try
{
context.MY_USER_GROUPS.RemoveRange(GetUserGroups(userName));
context.MY_USERS.Remove(new MY_USERS { USER_NAME = userName });
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw ex;
}
}
}
}
There is no no wrong or right, it just depends.
When you use IQueriable this mean that you can have common queries in your repository class and outside of it you can append additional filter.
GetAllUsers().Where(u=>u.UserType== 'Test').ToList()
You can also use include depends on your needs let say in MVC controller
GetAllUsers().Include(u=>u.Roles).Take(10).ToList();
Important thing to note, EF dont connect to db until you do ToList() or iterate throw query.
Lastly as you mentioned in comment always need to remember when you use IQuerieable that context could be disposed so this should be taken to consideration too.
On the other side could be good option return IEnumerable from repositories, so lets say if you want to load users you should have method which will require input parameters for paging, filtering or other stuff. This is useful for testing because you will be able to mock data.
About Delete it always depends on your requirements and if you need to remove all together or nothing than you need to use transactions IN addition it could be same about all CRUD.
I have the following Linq to SQL structure: I have the classes "Article" and "User". Each Article has a Seller (which is a User) and each User has many Articles. I solved that with an association.
And then I have an method Read(), which gets all Articles and returns it in a list.
public static List<Article> Read()
{
using (DataContext dbx = new DataContext())
{
return dbx.Article.ToList();
}
}
So, the problem now is: When I use the list anywhere in my program and I want to access article.Seller, I get the following exception:
Cannot access a disposed object
Okay, this seems legit, because I return the list and then DataContext is disposed. If I want to access the seller, it will be loaded from the database and thats not possible anymore with disposed DataContext.
So I solved that with lazy-loading and set the DeferredLoadingEnabled property to false.
To load the Seller, I used the DataLoadOptions.
public static List<Article> Read()
{
using (DataContext dbx = new DataContext())
{
dbx.DeferredLoadingEnabled = false;
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Article>(a => a.Seller);
dbx.LoadOptions = options;
return dbx.Article.ToList();
}
}
Okay, that works so far, but in one level only. Now I can access article.Seller, but if I'd like to get the other articles of that seller (article.Seller.Articles), I get null.
Just load with the articles of the Seller options.LoadWith<User>(u => u.Articles); I thought, but that is also not possible, because it would be endless.
Article -> Seller -> Articles -> each Article a Seller -> Articles -> again Seller -> ...
I get the exception
Cycles not allowed in LoadOptions LoadWith type graph.
What I want, is a method to get all the articles with correct association objects, like shown in my first method.
The association objects should always be accessible, but only loaded from database when accessed.
This would be possible if I use the DataContext everywhere I need the list in the program and then work with the list only in the DataContext.
But that would be very laborious.
Have you guys any idea how to get access to the association objects without writing the code of my Read() method everywhere in my program I need the list?
I have come across this in the past as well. The general practice is that you don't call Dispose() if you are going to allow deferred loading. In fact, calling Dispose() is not really required at all.
There is quite a lot written about whether or not to call Dispose() on the DataContext. You'll have to sift through it, but there's a nice article here. Basically, because the DataContext manages its connections itself, it doesn't really have any connections that need to be disposed explicitly.
I have an entity with a collection property that looks something like this:
public class MyEntity
{
public virtual ICollection<OtherEntity> Others { get; set; }
}
When I retrieve this entity via the data context or repository, I want to prevent others adding items to this collection through the use of MyEntity.Others.Add(entity). This is because I may want some validation code to be performed before adding my entity to the collection. I'd do this by providing a method on MyEntity like this:
public void AddOther(OtherEntity other)
{
// perform validation code here
this.Others.Add(other);
}
I've tested a few things so far, and what I've eventually arrived at is something like this. I create a private collection on my entity and expose a public ReadOnlyCollection<T> so MyEntity looks like this:
public class MyEntity
{
private readonly ICollection<OtherEntity> _others = new Collection<OtherEntity>();
public virtual IEnumerable<OtherEntity>
{
get
{
return _others.AsEnumerable();
}
}
}
This seems to be what I'm looking for and my unit tests pass fine, but I haven't yet started to do any integration testing so I'm wondering:
Is there a better way to achieve what I'm looking for?
What are the implications I'll face if I decide to go down this route (if feasible)?
Thanks always for any and all help.
Edit 1 I've changed from using a ReadOnlyCollection to IEnumerable and am using return _others.AsEnumerable(); as my getter. Again unit tests pass fine, but I'm unsure of the problems I'll face during integration and EF starts building these collections with related entities.
Edit 2 So, I decided to try out suggestions of creating a derived collection (call it ValidatableCollection) implementing ICollection where my .Add() method would perform validation on the entity provided before adding it to the internal collection. Unfortunately, Entity Framework invokes this method when building the navigation property - so it's not really suitable.
I would create collection class exactly for this purpose:
OtherEntityCollection : Collection<OtherEntity>
{
protected override void InsertItem(int index, OtherEntity item)
{
// do your validation here
base.InsertItem(index, item);
}
// other overrides
}
This will make much more rigid, because there will be no way to bypass this validation. You can check more complex example in documentation.
One thing I'm not sure is how to make EF create this concrete type when it materializes data from database. But it is probably doable as seen here.
Edit:
If you want to keep the validation inside the entity, you could make it generic through custom interface, that the entity would implement and your generic collection, that would call this interface.
As for problems with EF, I think the biggest problem would be that when EF rematerializes the collection, it calls Add for each item. This then calls the validation, even when the item is not "added" as business rule, but as an infrastructure behavior. This might result in weird behavior and bugs.
I suggest returning to ReadOnlyCollection<T>. I've used it in similar scenarios in the past, and I've had no problems.
Additionally, the AsEnumerable() approach will not work, as it only changes the type of the reference, it does not generate a new, independent object, which means that this
MyEntity m = new MyEntity();
Console.WriteLine(m.Others.Count()); //0
(m.Others as Collection<OtherEntity>).Add(new OtherEntity{ID = 1});
Console.WriteLine(m.Others.Count()); //1
will successfully insert in your private collection.
You shouldn't use AsEnumerable() on HashSet, because collection can be easily modified by casting it to ICollection<OtherEntity>
var values = new MyEntity().Entities;
((ICollection<OtherEntity>)values).Add(new OtherEntity());
Try to return copy of a list like
return new ReadOnlyCollection<OtherEntity>(_others.ToList()).AsEnumerable();
this makes sure that users will recieve exception if they will try to modify it. You can expose ReadOnlyCollection as return type enstead of IEnumerable for clarity and convenience of users. In .NET 4.5 a new interface was added IReadOnlyCollection.
You won't have big integration issues except some component depend on List mutation. If users will call ToList or ToArray, they will return a copy
You have two options here:
1) The way you are currently using: expose the collection as a ReadOnlyCollection<OtherEntity> and add methods in the MyEntity class to modify that collection. This is perfectly fine, but take into account that you are adding the validation logic for a collection of OtherEntity in a class that just uses that collection, so if you use collections of OtherEntity elsewhere in the project, you will need probably need to replicate the validation code, and that's a code smell (DRY) :P
2) To solve that, the best way is to create a custom OtherEntityCollection class implementing ICollection<OtherEntity> so you can add the validation logic there. It's really simple because you can create a simple OtherEntityCollection object that contains a List<OtherEntity> instance which really implements the collection operations, so you just need to validate the insertions:.
Edit: If you need custom validation for multiple entities you should create a custom collection which receives some other object that perform that validation. I've modified the example below, but it shouldn't be difficult to create a generic class:
class OtherEntityCollection : ICollection<OtherEntity>
{
OtherEntityCollection(Predicate<OtherEntity> validation)
{
_validator = validator;
}
private List<OtherEntity> _list = new List<OtherEntity>();
private Predicate<OtherEntity> _validator;
public override void Add(OtherEntity entity)
{
// Validation logic
if(_validator(entity))
_list.Add(entity);
}
}
EF can't map property without setter. or even private set { } requires some configuration. keep models as POCO, Plain-Old like DTO
the common approach is to create separated service layer that contain validation logic against your Model before save.
for sample..
public void AddOtherToMyEntity(MyEntity myEntity, OtherEntity otherEntity)
{
if(myService.Validate(otherEntity)
{
myEntity.Others.Add(otherEntity);
}
//else ...
}
ps. You could prevent compiler to do somethings but not other coders. Just made your code explicitly says "don't modify Entity Collection directly, until it passed validation"
Finally have a suitable working solution, here's what I did. I'll change MyEntity and OtherEntity to something more readable, like Teacher and Student where I want to stop a teacher teaching more students than they can handle.
First, I created an interface for all entities that I intend to validate in this way called IValidatableEntity that looks like this:
public interface IValidatableEntity
{
void Validate();
}
Then I implement this interface on my Student because I'm validating this entity when adding to the collection of Teacher.
public class Student : IValidatableEntity
{
public virtual Teacher Teacher { get; set; }
public void Validate()
{
if (this.Teacher.Students.Count() > this.Teacher.MaxStudents)
{
throw new CustomException("Too many students!");
}
}
}
Now onto how I invoke validate. I override .SaveChanges() on my entity context to get a list of all entities added and for each invoke validate - if it fails I simply set its state to detached to prevent it being added to the collection. Because I'm using exceptions (something I'm still unsure of at this point) as my error messages, I throw them out to preserve the stack trace.
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == System.Data.EntityState.Added)
{
if (entry.Entity is IValidatableEntity)
{
try
{
(entry.Entity as IValidatableEntity).Validate();
}
catch
{
entry.State = System.Data.EntityState.Detached;
throw; // preserve the stack trace
}
}
}
}
return base.SaveChanges();
}
This means I keep my validation code nicely tucked away within my entity which will make my life a whole lot easier when mocking my POCOs during unit testing.
I am currently using a DbContext similar to this:
namespace Models
{
public class ContextDB: DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
public ContextDB()
{
}
}
}
I am then using the following line at the top of ALL my controllers that need access to the database. Im also using it in my UserRepository Class which contains all methods relating to the user (such as getting the active user, checking what roles he has, etc..):
ContextDB _db = new ContextDB();
Thinking about this, there are occasions when one visitor can have multiple DbContexts active, for instance if it is visiting a controller that uses the UserRepository, which might not be the best of ideas.
When should I make a new DbContext? Alternatively, should I have one global context that is passed around and reused in all places? Would that cause a performance hit? Suggestions of alternative ways of doing this are also welcome.
I use a base controller that exposes a DataBase property that derived controllers can access.
public abstract class BaseController : Controller
{
public BaseController()
{
Database = new DatabaseContext();
}
protected DatabaseContext Database { get; set; }
protected override void Dispose(bool disposing)
{
Database.Dispose();
base.Dispose(disposing);
}
}
All of the controllers in my application derive from BaseController and are used like this:
public class UserController : BaseController
{
[HttpGet]
public ActionResult Index()
{
return View(Database.Users.OrderBy(p => p.Name).ToList());
}
}
Now to answer your questions:
When should I make a new DbContext / should I have one global context
that I pass around?
The context should be created per request. Create the context, do what you need to do with it then get rid of it. With the base class solution I use you only have to worry about using the context.
Do not try and have a global context (this is not how web applications work).
Can I have one global Context that I reuse in all places?
No, if you keep a context around it will keep track of all the updates, additions, deletes etc and this will slow your application down and may even cause some pretty subtle bugs to appear in your application.
You should probably chose to either expose your repository or your Context to your controller but not both. Having two contexts being access from the same method is going to lead to bugs if they both have different ideas about the current state of the application.
Personally, I prefer to expose DbContext directly as most repository examples I have seen simply end up as thin wrappers around DbContext anyway.
Does this cause a performance hit?
The first time a DbContext is created is pretty expensive but once this has been done a lot of the information is cached so that subsequent instantiations are a lot quicker. you are more likely to see performance problems from keeping a context around than you are from instantiating one each time you need access to your database.
How is everyone else doing this?
It depends.
Some people prefer to use a dependency injection framework to pass a concrete instance of their context to their controller when it is created. Both options are fine. Mine is more suitable for a small scale application where you know the specific database being used isn't going to change.
some may argue that you can't know this and that is why the dependency injection method is better as it makes your application more resilient to change. My opinion on this is that it probably won't change (SQL server & Entity Framework are hardly obscure) and that my time is best spent writing the code that is specific to my application.
I try to answer out of my own experience.
1. When should I make a new DbContext / should I have one global context that I pass around?
The Context should be injected by the dependency-injection and should not be instantiated by yourself. Best-Practice is to have it created as a scoped service by the dependency-injection. (See my answer to Question 4)
Please also consider using a proper layered application structure like Controller > BusinessLogic > Repository. In this case it would not be the case that your controller receives the db-context but the repository instead. Getting injected / instantiating a db-context in a controller tells me that your application architecture mixes many responsibilities in one place, which - under any circumstances - I cannot recommend.
2. Can i have one global Context that I reuse in all places?
Yes you can have but the question should be "Should I have..." -> NO. The Context is meant to be used per request to change your repository and then its away again.
3. Does this cause a performance hit?
Yes it does because the DBContext is simply not made for being global. It stores all the data that has been entered or queried into it until it is destroyed. That means a global context will get larger and larger, operations on it will get slower and slower until you will get an out of memory exceptions or you die of age because it all slowed to a crawl.
You will also get exceptions and many errors when multiple threads access the same context at once.
4. How is everyone else doing this?
DBContext injected through dependency-injection by a factory; scoped:
services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
I hope my answers where of help.
In performance point of view, DbContext should be created just when it is actually needed, For example when you need to have list of users inside your business layer,you create an instance form your DbContext and immediately dispose it when your work is done
using (var context=new DbContext())
{
var users=context.Users.Where(x=>x.ClassId==4).ToList();
}
context instance will be disposed after leaving Using Block.
But what would happen if you do not dispose it immediately?
DbContext is a cache in the essence and the more you make query the more memory blocks will be occupied.
It will be much more noticeable in case of concurrent requests flooding towards your application, in this case,each millisecond that you are occupying a memory block would be of the essence, let alone a second.
the more you postpone disposing unnecessary objects the more your application is closed to crash!
Of course in some cases you need to preserve your DbContext instance and use it in another part of your code but in the same Request Context.
I refer you to the following link to get more info regarding managing DbContext:
dbcontext Scope
You should dispose the context immediately after each Save() operation. Otherwise each subsequent Save will take longer. I had an project that created and saved complex database entities in a cycle. To my surprise, the operation became three times faster after I moved
using (var ctx = new MyContext()){...}
inside the cycle.
Right now I am trying this approach, which avoids instantiating the context when you call actions that don't use it.
public abstract class BaseController : Controller
{
public BaseController() { }
private DatabaseContext _database;
protected DatabaseContext Database
{
get
{
if (_database == null)
_database = new DatabaseContext();
return _database;
}
}
protected override void Dispose(bool disposing)
{
if (_database != null)
_database.Dispose();
base.Dispose(disposing);
}
}
This is obviously an older question but if your using DI you can do something like this and scope all your objects for the lifetime of the request
public class UnitOfWorkAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
context.BeginTransaction();
}
public override void OnActionExecuted(HttpActionExecutedContext actionContext)
{
var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
context.CloseTransaction(actionContext.Exception);
}
}
I am quite new to the FNH and NH world, so be gentle :P
I have created an application using FNH for data access which works good while not using lazy-loading, however once I enable lazy-loading everything goes pear shaped (as in, no sessions are open when I attempt to access the lazy-loaded properties etc).
The application layout I have created thus-far has a "Database" singleton which has various methods such as Save(), Refer() and List().
When calling Refer() a session is opened, the data is retrieved and the session is disposed; meaning there is no session available when attempting to access a lazy-loaded property from the returned object. Example: Database.Refer("username").Person since Person is lazy-loaded and the session has already closed.
I have read that Castle has a SessionManager that could be used for this very scenario but, either it's the late nights or lack of coffee, I can't seem to work out how to hook up FNH to use this manager as, in the spirit of castle, everything is defined in config files.
Am I missing something, or can this not be done? Are there any other session managers (or even more appropriate conventions) that I should look at?
Thanks for any help on this matter.
I don't think that your particular problem is connected with the SessionManager as you've already mentioned that you are capable of starting a new session and disposing it whenever needed.
From what I can understand of your post is that you are trying to expose an entity to your view (with some lazy-loaded properties) - which is already a bad idea because it leads to nasty LazyInitializationException(s).
You should consider making a distinguishion between your data-model and your domain model. The key concept has been described on this blog:
Ayende # Rahien
http://ayende.com/blog/4054/nhibernate-query-only-properties
If you say that you are writing a very simple 2-tier application then it probably will not harm if you will micro-manage your session in the data-layer (but keep in mind that this is not the best solution).
I would also look into the query that fetches your entity, as it seems to me that your are trying to obtain data that is just a part of your model - in this case Person. This can lead into serious problems like n+1 selects:
What is SELECT N+1?
So in general I think you should focus more on how things are structured in your application instead of searching for a SessionManager as it will not resolve all of your problems.
For any of you who are still looking for answers on this, I will share with you what I have so far.
This is only a very simple overview of the framework that I have decided to use, and is by far not the only solution for this problem.
The basic layout of my code is as follows:
NHibernate Repository
(references my model assembly and the UoW assembly)
Based on the HibernatingRhino's Repository implementation modified to suit my needs. Found here: http://ayende.com/Wiki/Rhino+Commons.ashx
public T Get(Guid Id)
{
return WrapUOW(() =>
{
using (Audit.LockAudit())
return (T)Session.Get(typeof(T), Id);
});
}
public void LoadFullObject(T partial)
{
if (partial == null)
throw new ArgumentNullException("partial");
if (partial.Id == Guid.Empty)
return;
WrapUOW(() =>
{
using (Audit.LockAudit())
{
LazyInitialiser.InitialiseCompletely(partial, Session);
}
});
}
public T SaveOrUpdate(T entity)
{
using (Audit.LockAudit())
{
With.Transaction(() =>
{
Enlist(entity);
Session.SaveOrUpdate(entity);
entity.HasChanged = false;
});
}
return entity;
}
protected void Enlist(T instance)
{
if (instance != null && instance.Id != Guid.Empty && !Session.Contains(instance))
using (Audit.LockAudit())
{
Session.Update(instance);
}
}
References a neat little helper class called 'Lazy Initializer for NHibernate' found here: http://www.codeproject.com/KB/cs/NHibernateLazyInitializer.aspx
This also contains Extension methods for Save, Delete and LoadFullObject
Have broken standards a little in this assembly by also creating a WrapUOW method to help simplify some of my code
protected static T WrapUOW(Func action)
{
IUnitOfWork uow = null;
if (!UnitOfWork.IsStarted)
uow = UnitOfWork.Start();
T result = action();
if (uow != null)
uow.Dispose();
return result;
}
NHibernate Unit of work
(references my model assembly)
Also based on the HibernatingRhino's UoW implementation and modified to suit
View - not important, just requried for MVVM implementation
Binds the values from the ViewModel
Model
Contains my entity classes and hibernate mapping files
ViewModel
Contains two main view base classes, ListPage and MaintenancePage
The ListPage base class just calls the Repository List method based on the object type we are listing. This loads a dehydrated list of entities.
The MaintenancePage takes an entity instance from the ListPage and calls the Repository.LoadFullObject method to rehydrate the entity for use on the screen.
This allows for the use of binding on the screen.
We can also safely call the Repository.SaveOrUpdate method from this page