How Entity Framework DbContext works in static method per web request? is there any performance issue? I have 2 classes below . Which one is better to use ? or bad? Do we need get instance all pear request ? is there any issue?
public class MyClassA
{
public static Product GetProduct(int Id)
{
using(MyContext myContext = new MyContext())
return myContext.Products.Where(x = > x.Id == Id).SingleOrDefault();
}
}
public class MyClassB
{
MyContext myContext = new MyContext()
public static Product GetProduct(int Id)
{
return myContext.Products.Where(x = > x.Id == Id).SingleOrDefault();
}
}
Call in Controller
public class DefaultController : ControllerBase
{
public Product GetProductStaticMethodinMyClassA(int Id)
{
return MyClassA.GetProduct(Id);
}
public Product GetProductStaticMethodinMyClassB(int Id)
{
return MyClassB.GetProduct(Id);
}
public Product GetProductinRequlurUse(int Id)
{
MyContext myContext = new MyContext();
return myContext.Products.Where(x => x.Id == Id).SingleOrDefault();
}
}
You need to create one DbContext per HTTP request... i.e. do not share the same DbContext between multiple requests.
C# Garbage Collector would automatically dispose of DbContext once it goes out of scope, so you don't have to put it in a using block, but having said that, most people do use using block and MS seems to encourage it:
The lifetime of the context begins when the instance is created and
ends when the instance is either disposed or garbage-collected. Use
using if you want all the resources that the context controls to be
disposed at the end of the block. When you use using, the compiler
automatically creates a try/finally block and calls dispose in the
finally block.
public void UseProducts()
{
using (var context = new ProductContext())
{
// Perform data access using the context
}
}
About usage of DbContext in your controller, your question is about design and opinion based... if you follow DDD principles, DbContext goes into Infrastructure Layer and your Controllers belongs to Presentation Layers... so you would not use DbContext directly in the controller at the first place.
If you want to use DbContext inside your controller, it is better to inject it, than to initialize it in the controller, initializing DbContext inside a controller violates SRP, because it is not controller's concern to initialize DbContext.
Related
I have the following unit of work pattern set up for an MVC 5 application using Entity Framework. The unit of work has all the repos defined as follows so that they are all using the same dbcontext and it has one save method to co-ordinate the transaction using the same context:
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public IProductRepository ProductRepository { get; private set; }
public ICustomerRepository CustomerRepository { get; private set; }
// Other reposistories
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
ProductRepository = new ProductRepository(_context);
CustomerRepository = new CustomerRepository(_context);
// Other reposistories
}
public void Complete()
{
_context.SaveChanges();
}
}
This is an example of my repo. The reason for using repos is for code re-use so that I'm not duplicating queries inside different controllers.
public class ProductRepository : IProductRepository
{
private readonly ApplicationDbContext _context;
public ProductRepository(ApplicationDbContext context)
{
_context = context;
}
public Product GetProduct(int productId)
{
return _context.Ticket.SingleOrDefault(p => p.Id == productId);
}
public void Add(Product product)
{
_context.Product.Add(product);
}
// Other methods
}
I inject the unit of work class in my controller as follows using Ninject:
public class ProductsController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly IFileUploadService _FileUploadService;
public ProductsController(IUnitOfWork unitOfWork,
IFileUploadService fileUploadService)
{
_unitOfWork = unitOfWork;
_FileUploadService = fileUploadService;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateEditProductViewModel viewModel)
{
var product = new Product
{
// Do stuff
};
_unitOfWork.ProductRepository.Add(product);
// Call file upload service
_fileUploadService.Upload();
_unitOfWork.Complete();
}
}
This unit of work set up works fine if all I'm using are repos that are defined in the unit of work class. But now I want to use a service class to process some additional application logic and then the unit of work is committed in the controller action. If I define the class as follows it will be using a different instance of the context, In which case how would you co-ordinate a transaction where the service layers is ending up with a different context?
public class FileUploadService : IFileUploadService
{
private readonly IUnitOfWork _unitOfWork;
public FileUploadService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public uploadResult Upload()
{
// Some stuff
var uploadedFile = new UploadedFile
{
//some stuff
};
_unitOfWork.UploadedFileRepository.Add(uploadedFile);
}
}
I've done quite a bit of research online and I'm unable to find any resource that provides a practical example to solve this problem. I've read quite a bit of stuff on ditching unit of work and repos and simply using entity frameworks dbset. However as explained above the purpose of using
repos is to consolidate queries. My questions is how do I co-ordinate the unit of work with a service class.
I would like the service to use the same context so that it can access the repositories it needs to work with, and let the controller (client code) commit the operation when it see fits.
* UPDATE *
In my DI Container I resolve all interfaces using the following snippet:
private static IKernel CreateKernel()
{
RegisterServices(kernel);
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
// default binding for everything except unit of work
kernel.Bind(x => x.FromAssembliesMatching("*")
.SelectAllClasses()
.Excluding<UnitOfWork>()
.BindDefaultInterface());
return kernel;
}
Would adding the line kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); ensure that no more than one ApplicationDbContext is created, even if the request ends up hitting multiple controllers or service layers that all require an IUnitOfWork (ApplicationDbContext)?
If you are using MVC, then your unit of work is your web request. If I were you I'd ditch the UOW implementation and just make sure you dbcontext is instantiated in the Application_BeginRequest. Then I'd stuff it into the HttpContext for safe keeping. On Application_EndRequest, I dispose of the DbContext.
I would move the save to your repository.
I'd create a [Transaction] attribute that would maintain a TransactionScope something like this:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : ActionFilterAttribute
{
private TransactionScope Transaction { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Transaction = new TransactionScope( TransactionScopeOption.Required);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
{
Transaction.Complete();
return;
}
Transaction.Dispose();
}
}
You can then just tag your controller methods with [Transaction].
I'm just spitballing here, but I do something similar with NHibernate instead of EF and it works out nicely for me.
The InRequestScope() will create a new instance of the bound type on every new web request, and at the end of that web request, it will Dispose that instance if it is disposable.
I am not sure how are you passing the ApplicationDbContext into your UnitOfWork. I am assuming that you use Ninject for this injection too. Just make sure that you bind your ApplicationDbContext using the InRequestScope()Bind.To().InRequestScope();.
This way, your ApplicationDbContext instance will be created once per request and disposed at the end.
Also, the use of InRequestScope is for types that are disposable, so you can also release resoruces in the Dispose method of your UnitOfWork method too.
Hi I have model class which is written in MVC.I am using Ef database first approach. In model class I have some queries which deals with database. I have following questions :
1) Is it right way to use database related queries in Model and call that in controller or view?
2)If yes where I should call this model? In Controller or in view ??
3)How I should call this model? Say for example I have class called class1.cs in model.How I should call this model?
Your model contains classes that define the different objects troughout your project. This includes properties with their basic information and methods to perform actions on this object.
1)
Do you really need queries? Why not use the Entity Framework to do it for you? Create the mapping for your domain classes (either trough annotations or fluent api) and use the DbContext to retrieve and save the data stored in your database
2)
Ideally people create repositories that are injected into your controllers (Dependency Injection). These repositories can for example contain something like GetPersonById(int id). Inside this method there would be two things:
Perform an action on the domain object
Save it to the DbContext
For example:
public void Subscribe(int userID, Show show) {
var user = GetUserByID(userID);
if (!user.IsSubscribedTo(show.ShowID)) {
user.Subscribe(show);
_dbContext.SaveChanges();
}
}
Controller -> Method call in repository -> Perform action on corresponding domain object -> Save changes to the database
If you need something that doesn't require an object mutation, it's even more simple:
public User GetUserByID(int id) {
return _dbContext.Users.FirstOrDefault(x => x.ID == id);
}
3)
Trough repositories (see above). Your DbContext will have a bunch of DbSets that contain objects that correspond with every data entry in your database. Trough repositories you can work with these objects and manipulate them. When you call the DbContext.SaveChanges() method, it will look at what has changed in these lists and commit the changes to your database.
Repository example:
class User {
public int ID { get; set; }
public string Name { get; set; }
}
class DatabaseContext : DbContext {
public DbSet<User> Users { get; set; }
}
public interface IUserRepository {
User GetUserByID (int id);
bool UsernameExists (string name);
}
public class UserRepository : IUserRepository {
private DatabaseContext _db;
public UserRepository(DatabaseContext db){
_db = db;
}
public User GetUserByID(int id) {
return _db.Users.FirstOrDefault(x => x.ID == id);
}
public User GetUserByUsername(string username) {
return _db.Users.FirstOrDefault(x => x.Name == username);
}
}
public class UserController : Controller {
private IUserRepository _userRepository;
public UserController(IUserRepository userRepository) {
_userRepository = userRepository;
}
public ActionResult Details(int id){
return View(_userRepository.GetUserByID(id);
}
}
// Ninject settings (install this extension, you want it):
private void AddBindings(){
kernel.Bind<DatabaseContext>().ToSelf().InSingletonScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
}
You could use some sort of Unit Of Work pattern which you inject in your controller constructor using an inversion of control container (IOC), for instance autofac.
Your unit of work class could hold a reference to repositories, where you would query/insert your data.
Roughly;
public class BackendController : Controller
{
private UnitOfWork _worker;
public BackendController(UnitOfWork worker)
{
this._worker = worker;
}
public ActionResult Admin()
{
var items = _worker.MyRepository.GetAll();
return View(items);
}
}
public class UnitOfWork
{
private ContentRepository _contentRepository;
public UnitOfWork()
{
}
public ContentRepository MyRepository
{
get
{
if (_contentRepository != null)
return _contentRepository;
else
return _contentRepository = new ContentRepository();
}
}
}
public class ContentRepository
{
// holds an object context and methods to retrieve and put data (EF or similar)
}
You would have to register your instance with the IOC container in global.asax, application_start for example, something like this (Using autofac as IOC):
UnitOfWork worker = new UnitOfWork();
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(worker).SingleInstance();
var container = builder.Build();
...
1) Is it right way to use database related queries in Model and call that in controller or view?
I would recommend not directly accessing the database in your model classes, as you have to remember that MVC is strictly a presentation layer pattern. If you do put your database access logic in your model classes, then you will not be able to have any other client use this functionality, such as a web service. Instead have logic that translates your business objects, defined outside of your ASP.NET MVC project, into your ASP.NET MVC model classes.
This is where the power of n-tier architecture shines, if you create a business and data-access layer, then I could write an ASP.NET MVC front-end, WebForms front-end, WPF front-end, WinForms front-end and all of them could access data using the same service. By putting the logic into the ASP.NET MVC model classes, then you are effectively forcing any other client to duplicate that logic again in their classes.
I have my Entity Framework Entities split out into a separate class library from my web project and data access layer. In my controller I make a call to my repository to get an IEnumerable<RobotDog.Entities.Movie> and then try to serialize into json using JavaScriptSerializer but I get a circular reference even though I'm using the [ScriptIgnore] attribute.
IMPORTANT: Originally I had my entities, data access and web all under one project and I was able to successfully serialize my entites without a circular reference. When I created separate layers that's when I started having problems. I did not change any of the entities.
An example of one of my entities in the RobotDog.Entities namespace:
namespace RobotDog.Entities {
public class Character {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(200)]
public string Name { get; set; }
public virtual Person Person { get; set; }
[ScriptIgnore]
public virtual Movie Movie { get; set; }
}
}
My controller:
namespace RobotDog.Web.Controllers {
public class MoviesController : Controller {
private UnitOfWork _unitOfWork = new UnitOfWork();
[HttpGet]
public ActionResult Index() {
var user = Membership.GetUser(User.Identity.Name);
if(user != null) {
var movies = _unitOfWork.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey).Select(m => m.Movie);
var serializer = new JavaScriptSerializer();
var json = serializer.Serialize(movies);
return View(json);
}
return View();
}
}
}
My Repository:
namespace RobotDog.DataAccess.Movies {
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
internal MovieContext Context;
internal DbSet<TEntity> DbSet;
public Repository(MovieContext context) {
if (context == null)
throw new ArgumentNullException("context");
Context = context;
DbSet = Context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null ) {
IQueryable<TEntity> query = DbSet;
if (predicate != null)
query = query.Where(predicate);
return orderBy != null ? orderBy(query).ToList() : query.ToList();
}
}
}
Maybe kinda late response, but I had similar problem with POCO Classes for Entity Framework Code-Firts. The problem was that may properties were declared as virtual. In this case EF creates proxy class which overrides the virtual property. It seems that ScriptIgnore attribute is not by default applied on overriden properties, unless you use it like this:
[ScriptIgnore(ApplyToOverrides=true)]
Circular object graphs cannot be JSON serialized. And when you give it a second thought it actually makes sense. The correct way to handle this is to use view models. You should never pass your domain entities directly to your views. Always define a view model containing only the necessary properties that you want to be exposed.
I am sure that the client consuming this JSON doesn't care about having this circular object graph. So simply define a view model breaking this circular dependency and including only the properties you need.
Then all you have to do is map your domain model to the view model and pass this view model to a JsonResult (yeah that's another issue in your code - you are manually JSON serializing and writing plumbing code in your controller action instead of delegating this to the framework).
So:
[HttpGet]
public ActionResult Index()
{
var user = Membership.GetUser(User.Identity.Name);
if(user != null)
{
IEnumerable<Movie> movies = _unitOfWork
.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey)
.Select(m => m.Movie);
IEnumerable<MovieViewModel> moviesVm = ... map the domain model to your view model
return Json(moviesVm, JsonRequestBehavior.AllowGet);
}
// return an empty movies array
var empty = Enumerable.Empty<MovieViewModel>();
return Json(empty, JsonRequestBehavior.AllowGet);
}
The important thing you should be focusing right now on is defining the MovieViewModel class which will contain only the information that you want to expose to the client as JSON. Break all circular references. Feel free to have additional view models that this main view model is referencing in order to map other entities.
And most importantly : never pass your domain models to the view. Always define view models. This way your application is completely independent of the underlying data access technology you are using. You could modify your DAL layer as much as you like without impacting the UI part because this UI is represented by view models.
I'm new to Mvc.
Sorry to my english. ^^
I have some question about asp.net MVC session in the controller.
The Scenario things that I want to do is like follows..
First of all, My development circumstance is entityframework and mvc3.
When Someone logged in each one has different database. So, Each has connect different database.
So, Each person has his own session value which is database connection string. So far so good.
I have simple database Repository and at the each repository's constructor can change database connection.
At controller which calls Repository class, I need session value. But As I know Controller's construction can't keep session value. right?
I want your good advice. Thanks in advance.
Code samples are below:
public class MasterRepository
{
DBEntities _db;
public MasterRepository(string con)
{
_db = new DBEntities(con);
}
}
public class TestController : Controller
{
private string con;
MasterRepository _db;
public TestController()
{
_db = new MasterRepository(Session["conn"].ToString()); // Session is null I want to solve this Part...
}
public ActionResult Index()
{
string con = Session["conn"].ToString(); // Session is assigned.
return View();
}
}
These should explain what's happening to cause Session to be null, and give you a few possible solution options:
Is ASP.NET MVC Session available at any point durign controller construction
Why my session variables are not available at construction of a Controller?
Session null in ASP.Net MVC Controller Constructors
I think you have missed out the "service" part of the controller - service - repository pattern:
http://weblogs.asp.net/fredriknormen/archive/2008/04/24/what-purpose-does-the-repository-pattern-have.aspx
But when you go down this path you will probably also need to learn IoC as well.
Then your code would look more like:
public class MasterRepository
{
public Foo GetAllFoo()
{
return ObjectContextManager.GetObjectContext().AsQueryable().ToList();
}
}
public class MasterService
{
MasterRepository _repository;
public MasterService(MasterRepository repository) // use IoC
{
_repository = repository;
}
public Foo GetAllFoo()
{
return _repository.GetAllFoo();
}
}
public class TestController : Controller
{
MasterService _service;
public TestController(MasterService service) // use IoC
{
_service = service;
}
public ActionResult Index()
{
var model _service.GetAllFoo();
return View(model);
}
}
New to EF and I have noticed that using a repository pattern can really simplify things and will allow me to do some mocking too.So far so good.
My Question
A typical usage of the objectContext is to destroy as soon as possible see below
using (var context = new SchoolEntities())
{
context.AddToDepartments(department);
context.SaveChanges();
}
Using the Repository pattern I have noticed that nobody actually uses the "Using Pattern" eg
using (var repository= new Repository<Student>(new MyContext))
{
repository.Add(myStudentEntity)
repository.SaveChanges();
}
Should the idea be that we should dispose of the context as soon as possible otherwise the memory might leak or get very big?
Can anyone clarify? Thanks a lot.
Yes you should dispose context even if you are using repository. It is not clear what advantage does your Repository implementation give you because you are still providing ObjectContext as constructor's parameter, aren't you?
IMO the main reason for using Repository and custom UnitOfWork is persistance ignorance = hidding EF code from upper application layers because ObjectContext + ObjectSet themselves are implementation of repository and unit of work patterns.
If I'm using repository, I'm always wrapping whole EF code, so the public interface of my repository doesn't provide any information about EF related infrastructure. In that case it is up to me how I deal with ObjectContext.
For easy straight forward CRUD scenarios, I can wrap context creation and disposing into each repository method. In more complex scenarios I'm using additional class - UnitOfWork (UoW), which wraps context creation and disposing and it triggers saving changes into database. It also acts as factory for all repositories and passes instance of created context into repositories' constructors.
Most of the time I'm programming services or web applications so I'm dealing with detached objects. I'm always using single UoW instance for request processing. So the UoW is created at the beginning of request processing and released at the end of request processing. In case of WinForms / WPF applications and attached objects I think the good idea is to have UoW / ObjectContext instance "per form" - there is article describing this approach with NHibernate session (same as EF ObjectContext) in MSDN magazine.
Some starting implementation of UnitOfWork and Repository patterns:
Context holder and abstract factory for repositories
public interface IUnitOfWork
{
IRepository<MyEntity> MyEntityRepository { get; }
// Repositories for other entities
SaveChanges();
}
Repository for detached entities
public interface IRepository<T> where T : class
{
IQueryable<T> GetQuery();
void Insert(T entity);
void Delete(T entity);
// In very complex scenarios with big object graphs you will probably give up
// using detached approach and you will always load your entities from DB before
// deleting or updating them. In such case you will not need Update method at all.
void Update(T entity);
}
Disposable implementation of UnitOfWork wrapping Enitity framework
public class UnitOfWork : IUnitOfWork, IDisposable
{
private ObjectContext _context = null;
public UnitOfWork(string connectionString)
{
if (String.IsNullOrEmpty(connectionString)) throw new ArgumentNullException("connectionString");
_context = new ObjectContext(connectionString);
}
private IRepository<MyEntity> _myEntityRepository;
public IRepository<MyEntity> MyEntityRepository
{
get
{
return _myEntityRepository ?? (_myEntityRepository = new GeneralRepository<MyEntity>(_context));
}
}
public void SaveChanges()
{
_context.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
Base repository implementation
public class GeneralRepository<T> : IRepository<T> where T : class
{
private ObjectSet<T> _set;
private ObjectContext _context;
public GeneralRepository(ObjectContext context)
{
if (context == null) throw new ArgumentNullException("context");
_context = context;
_set = context.CreateObjectSet<T>();
}
// Override this method for example if you need Includes
public virtual IQueryable<T> GetQuery()
{
return _set;
}
// Override following methods if you are working with object graphs.
// Methods do not execute operations in database. It is responsibility of
// UnitOfWork to trigger the execution
public virtual void Insert(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
_set.AddObject(entity);
}
// These impelementations are for detached scenarios like web application
public virtual void Delete(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
_set.Attach(entity);
_set.DeleteObject(entity);
}
public virtual void Update(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
_set.Attach(entity);
_context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
}
Usage when selecting data
using (var uow = new UnitOfWork(connectionString))
{
var entity = uow.MyEntitiesRepository.GetQuery().Single(e => e.Id == 1);
// Do something with entity
}
Usage when modifing data
using (var uow = new UnitOfWork(connectionString))
{
uow.MyEntitiesRepository.Update(entity);
uow.SaveChanges();
}