How can I use Entity Framework 6 and my repository to delete multiple records? - asp.net-mvc

I am using Entity Framework 6 and I have a repository looking like the following with the Add and Update methods removed to make it shorter:
public class GenericRepository<T> : IRepository<T> where T : class
{
public GenericRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("An instance of DbContext is required to use this repository", "context");
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public virtual IQueryable<T> Find(Expression<Func<T, bool>> predicate)
{
return DbSet.Where<T>(predicate);
}
public virtual IQueryable<T> GetAll()
{
return DbSet;
}
public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}
In my controller I call the repository like this:
public HttpResponseMessage DeleteTest(int id)
{
Test test = _uow.Tests.GetById(id);
if (test == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
try
{
_uow.Tests.Delete(test);
_uow.Commit();
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
This works for a single test but how can I delete for example all tests that have an examId column value of 1 being
that examId is one of the columns in the Test table.

You can create another delete method in your generic repository class, see below:
public virtual void Delete(Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = DbSet.Where(predicate).AsQueryable();
foreach (T obj in query)
{
DbSet.Remove(obj);
}
}
Then you can use it like below, it will delete all records which Id equalsid.
_uow.Test.Delete(n => n.Id = id)

I'm not sure if EF is able to handle multiple delete now given a certain value, but the last time I did this I had to resort to a loop.
public HttpResponseMessage DeleteTest(int id)
{
var testList = _uow.Tests.GetAll().Where(o => o.Id == id);
if (testList.Count() == 0)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
try
{
foreach (var test in testList)
{
_uow.Tests.Delete(test);
}
_uow.Commit();
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
If the "test" table is a foreign table linked to a primary table on the "ID" column, you may want to consider doing a cascading delete in this case.

You can use RemoveRange()
public virtual void Delete(Expression<Func<T,bool>> predicate)
{
var query = Context.Set<T>().Where(predicate);
Context.Set<T>().RemoveRange(query);
}

Related

Problems implementing a simple ASP.NET Core Web API Service (PersonExample)

I am new to ASP.NET, ASP.NET MVC and Entity Framework (generally) and with the .NET Core variants (specifically). Currently I am trying to get my first example/test project running (in Visual Studio 2015) but having a couple of problems I couldn't find solutions for on Google.
Part of the tutorials & instructions I followed so far:
https://dzone.com/articles/how-to-create-rest-apiweb-api-with-aspnet-core-10 (for the first introduction)
http://www.restapitutorial.com/lessons/httpmethods.html (for what the web api should return)
https://docs.efproject.net/en/latest/platforms/aspnetcore/existing-db.html (create the DB and scaffold-dbcontext)
https://docs.asp.net/en/latest/fundamentals/logging.html (for the general use of loggers)
https://github.com/NLog/NLog.Extensions.Logging (for configuring Logging with NLog)
https://docs.asp.net/en/latest/tutorials/web-api-help-pages-using-swagger.html (for setting up and using swagger)
Those tutorials & instructions only describe a snippet of the solution each but those snippets do not fit together and cause problems. So I am trying to get the missing pieces together.
What I want to achieve is a (as simple as possible) example project:
ASP.NET Core Web API demo/example project (in Visual Studio 2015)
which stores data in a (SQL) database (not some handwritten repository) using Entity Framework Core (just 1 table Person holding 3 columns: id as primary key identity, 2 columns firstname and lastname defined as nvarchar(30))
where one can
request (GET) all persons (WORKS in the code below)
(GET) a specific person by id or by lastname (works in the code below)
create (POST) a new person (works in the code below)
(DELETE) a person by id (works in the code below)
full replace (PUT) by id (HOW TO DO?)
modify (PATCH) the last name (people still marry) only sending id and new last name (HOW TO DO?)
using a repository between the controller and the dbContext (for reusability of the repository functions)
have the controller to be standard conform (return correct error code/error results)
have working exception handling
My implementation in question:
IPersonRepository interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PersonExample.Models;
namespace PersonExample.Repository
{
public interface IPersonRepositoy
{
IEnumerable<Person> GetAll();
Person GetById(int id);
IEnumerable<Person> GetByLastname(string lastname);
IEnumerable<Person> SearchByLastname(string namePart);
int Create(Person item);
int Delete(int id);
int Replace(int id, Person item);
int Modify(int id, string newLastname);
}
}
PersonRepository implementation:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using PersonExample.Models;
namespace PersonExample.Repository
{
public class PersonRepository : IPersonRepositoy
{
private readonly PersonDbContext _dbContext;
private readonly ILogger<PersonRepository> _logger;
public PersonRepository(PersonDbContext dbContext, ILogger<PersonRepository> logger)
{
_dbContext = dbContext;
_logger = logger;
}
public IEnumerable<Person> GetAll()
{
//always returns an IEnumerable (even if it is empty)
_logger.LogDebug(string.Format("{0}.GetAll()", GetType().Name));
return _dbContext.Person;
}
public Person GetById(int id)
{
//SingleOrDefault() returns an instance of Person or null
_logger.LogDebug(string.Format("{0}.GetById({1})", GetType().Name, id));
return _dbContext.Person.Where(i => i.Id == id).SingleOrDefault();
}
public IEnumerable<Person> GetByLastname(string lastname)
{
//always returns an IEnumerable (even if it is empty)
_logger.LogDebug(string.Format("{0}.GetByLastname({1})", GetType().Name, lastname));
return _dbContext.Person.Where(i => i.Lastname == lastname);
}
public IEnumerable<Person> SearchByLastname(string namePart)
{
//always returns an IEnumerable (even if it is empty)
_logger.LogDebug(string.Format("{0}.SearchByLastname({1})", GetType().Name, namePart));
return _dbContext.Person.Where(i => i.Lastname.Contains(namePart));
}
public int Create(Person item)
{
_logger.LogDebug(string.Format("{0}.Create({1}) (id: {2}, firstname: {3}, lastname: {4})",
GetType().Name, item, item.Id, item.Firstname, item.Lastname));
//Add seems to be atomic > Attach would save linked objects too but seems to fail on simple objects
//what exceptions could occur to catch somewhere else (e.g. if lastname would have a unique constraint)?
_dbContext.Person.Add(item);
int res;
try
{
res = _dbContext.SaveChanges();
}
catch (Microsoft.EntityFrameworkCore.DbUpdateException e)
{
_logger.LogError(string.Format("", GetType().Name));
res = -1;
}
if (res == 0)
{
_logger.LogError(string.Format("{0}.Create({1}) -> no items were created/changed", GetType().Name, item));
}
else
{
_logger.LogDebug(string.Format("{0}.Create({1}) -> {2} item(s) were created/changed", GetType().Name, item, res));
}
return res;
}
public int Delete(int id)
{
_logger.LogDebug(string.Format("{0}.Delete({1}", GetType().Name, id));
Person item = _dbContext.Person.Where(i => i.Id == id).SingleOrDefault();
if (item != null)
{
_dbContext.Person.Remove(item);
int res = _dbContext.SaveChanges();
if (res == 0)
{
_logger.LogError(string.Format("{0}.Delete({1} -> no items deleted", GetType().Name, id));
}
else
{
_logger.LogDebug(string.Format("{0}.Delete({1} -> {2} item(s) deleted", GetType().Name, id, res));
}
return res;
}
else
{
_logger.LogError(string.Format("{0}.Delete({1} -> not item found by id", GetType().Name, id));
return -1; // better way to indicate not found?
}
}
public int Replace(int id, Person item)
{
// how to implement replace
throw new NotImplementedException();
}
public int Modify(int id, string newLastname)
{
// how to implement modify
throw new NotImplementedException();
}
}
}
PersonController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using PersonExample.Repository;
using PersonExample.Models;
namespace PersonExample.Controllers
{
[Route("api/[controller]")]
public class PersonController : Controller
{
private readonly IPersonRepositoy _repo;
private readonly ILogger<PersonRepository> _logger;
public PersonController(IPersonRepositoy repo, ILogger<PersonRepository> logger)
{
_repo = repo;
_logger = logger;
}
// GET: api/values
[HttpGet]
public IEnumerable<Person> Get()
{
_logger.LogDebug(string.Format("{0}.GetAll()", GetType().Name));
IEnumerable<Person> data = _repo.GetAll();
_logger.LogDebug(string.Format("{0}.GetAll() -> returned {1} result(s)", GetType().Name, "?"));
return data;
}
// GET api/values/5
[HttpGet("{id:int}", Name = "GetPerson")]
public IActionResult Get(int id)
{
_logger.LogDebug(string.Format("{0}.GetById({1})", GetType().Name, id));
Person item = _repo.GetById(id);
if (item == null)
{
_logger.LogError(string.Format("{0}.GetById({1}) -> no item found by id", GetType().Name, id));
return NotFound(id);
}
return new ObjectResult(item);
}
[HttpGet("{lastname}")]
public IEnumerable<Person> Get(string lastname)
{
// example to demonstrate overloading of types (int for id, string for lastname)
_logger.LogDebug(string.Format("{0}.GetByLastname()", GetType().Name));
IEnumerable<Person> data = _repo.GetByLastname(lastname);
_logger.LogDebug(string.Format("{0}.GetByLastname() -> returned {1} result(s)", GetType().Name, "?"));
return data;
}
[HttpGet("search/{namepart}")]
public IEnumerable<Person> Search(string namepart)
{
//example to demonstrate url modification (how would I do multiple name parts?)
_logger.LogDebug(string.Format("{0}.Search({1})", GetType().Name, namepart));
IEnumerable<Person> data = _repo.SearchByLastname(namepart);
_logger.LogDebug(string.Format("{0}.Search({1}) -> returned {2} result(s)", GetType().Name, namepart, "?"));
return data;
}
// POST api/values
[HttpPost]
public IActionResult Post([FromBody]Person value)
{
//how to validate data and what to return in error cases?
_logger.LogDebug(string.Format("{0}.Post({1})", GetType().Name, value));
if (value == null)
{
_logger.LogDebug(string.Format("{0}.Post({1}) -> bad request: item is null", GetType().Name, value));
return BadRequest();
}
//return 409 Conflict if resource exists -> where and how to check?
int res = _repo.Create(value);
if (res == 0) //no items changed
{
_logger.LogError(string.Format("{0}.Post({1}) -> zero items changed", GetType().Name, value));
return NotFound(); //what to return? not found isn't the problem
}
else if (res == -1) //DbUpdateException
{
_logger.LogError(string.Format("{0}.Post({1}) -> DbUpdateException", GetType().Name, value));
return NotFound(); //what to return? not found isn't the problem
}
_logger.LogDebug(string.Format("{0}.Post({1}) -> {2} items changed", GetType().Name, value, res));
return CreatedAtRoute("GetPerson", new { id = value.Id }, value);
}
// DELETE api/values/5
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
_logger.LogDebug(string.Format("{0}.Delete(id: {1})", GetType().Name, id));
int res = _repo.Delete(id);
if (res == 0) // zero entries changed
{
_logger.LogError(string.Format("{0}.Delete({1}) -> zero items changed", GetType().Name, id));
//what to return in that case, its a different error than not found???
return NotFound();
}
else if (res == -1) // id not found
{
_logger.LogError(string.Format("{0}.Delete({1}) -> not found item by id", GetType().Name, id));
return NotFound(id);
}
return Ok();
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]Person value)
{
//example for full update / complete replace with logging and error handling
// how to implement, what to return?
// _repo.Replace(id, value);
}
// PATCH api/values/5
[HttpPatch("{id}")]
public void Patch(int id, [FromBody]Person value)
{
//example for partial update with logging and error handling
// how to implement, what to return?
//_repo.Modify(id, lastname);
}
}
}
My Questions
In general:
What are the correct (and REST standard conform) implementations of the controller and the repository including exception handling, data validation (necessary?) and logging of errors (when one occurs)

Get recent inserted Id and send in to another controllers view

EDITED:
I have Created CRUD Functions for each Modals and now i am trying to get recent Inserted Id and use it in different view.
Here is what I have tried so far
I have created 2 classes(Layer based) for CRUD function for each ContextEntities db to practice pure OOP recursive approach and following is the code.
1. Access Layer
ViolatorDB
public class ViolatorDB
{
private TPCAEntities db;
public ViolatorDB()
{
db = new TPCAEntities();
}
public IEnumerable<tbl_Violator> GetALL()
{
return db.tbl_Violator.ToList();
}
public tbl_Violator GetByID(int id)
{
return db.tbl_Violator.Find(id);
}
public void Insert(tbl_Violator Violator)
{
db.tbl_Violator.Add(Violator);
Save();
}
public void Delete(int id)
{
tbl_Violator Violator = db.tbl_Violator.Find(id);
db.tbl_Violator.Remove(Violator);
Save();
}
public void Update(tbl_Violator Violator)
{
db.Entry(Violator).State = EntityState.Modified;
Save();
}
public void Save()
{
db.SaveChanges();
}
}
2. Logic Layer
ViolatorBs
public class ViolatorBs
{
private ViolatorDB objDb;
public ViolatorBs()
{
objDb = new ViolatorDB();
}
public IEnumerable<tbl_Violator> GetALL()
{
return objDb.GetALL();
}
public tbl_Violator GetByID(int id)
{
return objDb.GetByID(id);
}
public void Insert(tbl_Violator Violator)
{
objDb.Insert(Violator);
}
public void Delete(int id)
{
objDb.Delete(id);
}
public void Update(tbl_Violator Vioaltor)
{
objDb.Update(Vioaltor);
}
}
And Finally using Logic Layer functions in presentation Layer.Here insertion is performed as:
public class CreateViolatorController : Controller
{
public TPCAEntities db = new TPCAEntities();
private ViolatorBs objBs;
public CreateViolatorController()
{
objBs = new ViolatorBs();
}
public ActionResult Index()
{
var voilator = new tbl_Violator();
voilator=db.tbl_Violator.Add(voilator);
ViewBag.id = voilator.VID;
return View();
}
[HttpPost]
public ActionResult Create(tbl_Violator Violator)
{
try
{
if (ModelState.IsValid)
{
objBs.Insert(Violator);
TempData["Msg"] = "Violator Created successfully";
return RedirectToAction("Index");
}
else
{
return View("Index");
}
}
catch (Exception ex)
{
TempData["Msg"] = "Failed..." + ex.Message + " " + ex.ToString();
return RedirectToAction("Index");
}
}
}
Now here is the main part how do i get perticuller inserted id in another controller named Dues while performing insertion ?
In sqlqery I would have used ##IDENTITY but in Entity Framework I'm not sure.
I'm new to mvc framework any suggestion or help is appreciated Thanks in Advance.
Once you save your db context the id is populated back to your entity by EF automatically.
for example.
using(var context = new DbContext())
{
var employee = new Employee(); //this has an id property
context.Employees.Add(employee);
context.SaveChanges();
var id = employee.id; // you will find the id here populated by EF
}
You dont need to add and save your table as you have done this already in your voilatorDB class just fetch the last id like following
var id = yourTableName.Id;
db.yourTableName.find(id);
Or you can simply write one line code to achive that using VoilatorBs class function
GetbyID(id);

controller post actionresult not saving changes to database

I have a post method in my controller that is not saving changes to my database (SQL express). I am using viewmodels and valueinjector to populate the VM from my model. I have checked and the values in the viewmodel and they have changed, but when I call my service:
fixedAssetService.SaveFixedAsset()
and bookmark the following in the service interface:
unitOfWork.Commit()
and pull up the quick watch window for unitOfWork, it has the old value.
All my tables have primary keys and I am using code first. The connection string is valid becasue I can get the items, I just can't save them.
My post method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(FixedAssetViewModel evm)
{
var fixedAsset = fixedAssetService.GetFixedAsset(evm.FixedAssetId);
// Use Injector to handle mapping between viewmodel and model
fixedAsset.InjectFrom(evm);
try
{
if (ModelState.IsValid)
{
fixedAssetService.SaveFixedAsset();
return RedirectToAction("Details", "FixedAsset", new { id = fixedAsset.FixedAssetId });
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
My Service:
namespace FixedAssets.Services
{
public interface IFixedAssetService
{
IEnumerable<FixedAsset> GetAll();
IEnumerable<FixedAsset> FindBy(Expression<Func<FixedAsset, bool>> predicate);
FixedAsset GetFixedAsset(string id);
void CreateFixedAsset(FixedAsset fixedAsset);
void DeleteFixedAsset(string id);
void SaveFixedAsset();
bool ValueInUse(Expression<Func<FixedAsset, bool>> predicate);
}
public class FixedAssetService : IFixedAssetService
{
private readonly IFixedAssetRepository fixedAssetRepository;
private readonly IUnitOfWork unitOfWork;
public FixedAssetService(IFixedAssetRepository fixedAssetRepository, IUnitOfWork unitOfWork)
{
this.fixedAssetRepository = fixedAssetRepository;
this.unitOfWork = unitOfWork;
}
#region IFixedAssetService Members
public IEnumerable<FixedAsset> GetAll()
{
var fixedAssets = fixedAssetRepository.GetAll();
return fixedAssets;
}
public IEnumerable<FixedAsset> FindBy(Expression<Func<FixedAsset, bool>> predicate)
{
IEnumerable<FixedAsset> query = fixedAssetRepository.FindBy(predicate);
return query;
}
public bool ValueInUse(Expression<Func<FixedAsset, bool>> predicate)
{
IQueryable<FixedAsset> query = fixedAssetRepository.FindBy(predicate).AsQueryable();
int count = query.Count();
return count > 0 ? true : false;
}
public FixedAsset GetFixedAsset(string id)
{
var fixedAsset = fixedAssetRepository.GetById(id);
return fixedAsset;
}
public void CreateFixedAsset(FixedAsset fixedAsset)
{
fixedAssetRepository.Add(fixedAsset);
SaveFixedAsset();
}
public void DeleteFixedAsset(string id)
{
var fixedAsset = fixedAssetRepository.GetById(id);
fixedAssetRepository.Delete(fixedAsset);
SaveFixedAsset();
}
public void SaveFixedAsset()
{
unitOfWork.Commit();
}
#endregion
}
}
Edit: One thing I forgot to mention is this app was modeled almost exactly after an existing app that worked fine. Not sure if I have references messed up or what, but the other app uses the same methods only different entities
I found my problem. In the app I used as a model for this one I was using a separate unity class. My database factory registration was like this:
.RegisterType<IDatabaseFactory, DatabaseFactory>(new HttpContextLifetimeManager<IDatabaseFactory>())
Now I am using Microsoft.Practices.Unity and Unity.Mvc4 so I changed the registration to:
container.RegisterType<IDatabaseFactory, DatabaseFactory>();
per the comments in the bootstrapper class. When I changed it to:
container.RegisterType<IDatabaseFactory, DatabaseFactory>(new HierarchicalLifetimeManager());
per the suggestions on this post:
Stackoverflow thread
it finally worked!

How to execute function in MVC with Entity Framework?

how to use following function
Generic Function:
public T GetSingle(Expression<Func<T, bool>> whereCondition)
{
return this.ObjectSet.Where(whereCondition).FirstOrDefault<>();
}
Business logic wise:
//Now in the following function i would like to call Generic function.
public TabMasterViewModel GetSingle(Expression<Func<TabMasterViewModel, bool>> whereCondition)
{
_tabmasterRepository.GetSingle( .. what should be here.. );
}
//Calling function from Controller level.
public ActionResult Details(int id)
{
return View(_tabmasterService.GetSingle(x => x.colID == id));
}
I could not able to use the function, please suggest.
_tabmasterRepository.GetSingle( .. what should be here.. );
Thanks,
Imdadhusen
Either you modify your first generic function as
public T GetSingle(Expression<Func<T, bool>> whereCondition)
{
return context.CreateObjectSet<T>().Where(whereCondition).FirstOrDefault();
}
or create a genetic repository
public class RepositoryGeneric<TEntity>
{
public RepositoryGeneric(Context context)
{
Context = context;
}
protected ObjectContext Context { get; private set; }
protected virtual ObjectSet<TEntity> ObjectSet
{
get { return Context.CreateObjectSet<TEntity>(); }
}
public virtual TEntity GetByKey(params object[] keys)
{
return DbSet.Find(keys);
}
public TEntity GetSingle(Expression<Func<TEntity, bool>> whereCondition)
{
return ObjectSet.Where(whereCondition).FirstOrDefault();
}
}
Edit:
using the generic function
TabMasterViewModel model = _tabmasterService.GetSingle(x => x.colID == id);
or using generic repository
var tabmasterRepository = new RepositoryGeneric<TabMasterViewModel>(new Context());
var model = tabmasterRepository.GetSingle(x => x.colID == id);

Norm.MongoException: Connection timeout trying to get connection from connection pool

I'm using Rob's mvc startesite http://mvcstarter.codeplex.com/ with ASP.Net MVC 2, Ninject2, NoRM (http://github.com/atheken/NoRM) and MongoDB. It works so fast and the developpement is even faster but I'm facing a big problem, I at some points, get connection timeout. I can't figure out what I'm doing wrong.
I already asked a question here : I get this error that I don't understand why, using NoRM and Mongo in my MVC project and here http://groups.google.com/group/norm-mongodb/browse_thread/thread/7882be16f030eb29 but I still in the dark.
Thanks a lot for the help!
EDITED*
Here's my MongoSession object :
public class MongoSession : ISession{
private readonly Mongo _server;
public MongoSession()
{
//this looks for a connection string in your Web.config - you can override this if you want
_server = Mongo.Create("MongoDB");
}
public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class {
return _server.GetCollection<T>().AsQueryable().Where(expression).SingleOrDefault();
}
public IQueryable<T> All<T>() where T : class {
return _server.GetCollection<T>().AsQueryable();
}
public void Save<T>(IEnumerable<T> items) where T : class {
foreach (T item in items) {
Save(item);
}
}
public void Save<T>(T item) where T : class {
var errors = DataAnnotationsValidationRunner.GetErrors(item);
if (errors.Count() > 0)
{
throw new RulesException(errors);
}
_server.Database.GetCollection<T>().Save(item);
}
public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class
{
var items = All<T>().Where(expression);
foreach (T item in items)
{
Delete(item);
}
}
public void Delete<T>(T item) where T : class
{
_server.GetCollection<T>().Delete(item);
}
public void Drop<T>() where T : class
{
_server.Database.DropCollection(typeof(T).Name);
}
public void Dispose() {
_server.Dispose();
}
}
And now my MongoRepositoryBase
public abstract class MongoRepositoryBase<T> : ISession<T> where T : MongoObject
{
protected ISession _session;
protected MongoRepositoryBase(ISession session)
{
_session = session;
}
public T Single(ObjectId id)
{
return _session.All<T>().Where(x => x.Id == id).FirstOrDefault();
}
public T Single(Expression<Func<T, bool>> expression)
{
return _session.Single(expression);
}
public IQueryable<T> All()
{
return _session.All<T>();
}
public void Save(IEnumerable<T> items)
{
foreach (T item in items)
{
Save(item);
}
}
public void Save(T item)
{
_session.Save(item);
}
public void Delete(System.Linq.Expressions.Expression<Func<T, bool>> expression)
{
var items = _session.All<T>().Where(expression);
foreach (T item in items)
{
Delete(item);
}
}
public void DeleteAll()
{
var items = _session.All<T>();
foreach (T item in items)
{
Delete(item);
}
}
public void Delete(T item)
{
_session.Delete(item);
}
public void Drop()
{
_session.Drop<T>();
}
public void Dispose()
{
_session.Dispose();
}
}
And an exemple of an other Repository implemantation :
public class PlaceRepository : MongoRepositoryBase<Place>, IPlaceRepository
{
public PlaceRepository(ISession session) : base(session)
{
}
public List<Place> GetByCategory(PlaceCategory category, bool publishedOnly)
{
var query = _session.All<Place>()
.OrderBy(x => x.Name)
.Where(x => x.Category == category);
if (publishedOnly) query = query.Where(x => x.Published);
if (publishedOnly) query = query.Where(x => x.ShowOnMap);
return query.ToList();
}
public Place FindByName(string name)
{
var query = _session.All<Place>()
.Where(x => x.Name.ToLower().Contains(name.ToLower()))
.Where(x => x.Published);
return query.FirstOrDefault();
}
public string[] FindSuggestionsByName(string name)
{
var query = _session.All<Place>()
.OrderBy(x => x.Name)
.Where(x => x.Name.ToLower().StartsWith(name.ToLower()))
.Where(x => x.Published);
var places = query.ToList();
var names = new string[places.Count];
var i = 0;
foreach (var place in places)
{
names[i++] = place.Name;
}
return names;
}
}
Vinny,
I've never used Ninject, so I could be way off with this suggestion. But it seems possible that having a static MongoSession instance might be holding connections open. Have you tried TransientBehavior instead of SingletonBehavior? Or maybe change your code to call Dispose (or use using) after you convert your ShortcutLinks to a List? All
var shortcutLionks = _session.All<ShortcutLinks>().ToList();
_session.Dispose();
A better approach might be to use some sort of repository or DAO where the session details are hidden from the controller. I have a RepositoryBase sample at http://www.codevoyeur.com/Articles/20/A-NoRM-MongoDB-Repository-Base-Class.aspx.
Stuart Harris has a similar, arguably more complete implementation at http://red-badger.com/Blog/post/A-simple-IRepository3cT3e-implementation-for-MongoDB-and-NoRM.aspx
Pooled MongoDB connections are relatively cheap to create, so it's probably best to make sure the data access methods are disposing after your done getting/saving data.
If I add throw new NotImplementedException(); in the Dispose() method of my MongoRepositoryBase class it does not get call so I guess Ninject does not handle this for me, If I had
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
_recipeRepo.Dispose();
base.OnActionExecuted(filterContext);
}
In my controller it does get call. It seems to be fine, thx!

Resources