I have a project where i was working with object context earlier. Now for taking advantage of reading in memory data that is not saved into db yet I had to change my ObjectContext to DbContext as suggested here
But after the refactoring to DbContext my LinqQueries doesn't work at all.
Before:
With objectContext
var student1 = myContext.Students.First(); //No errors and Students is ObjectSet<Student> collection
After Change to DbContext but with the same code:
var student1 = myContext.Students.First(); //Error: There is no method called First() on DbSet<Student>....
What could be the issue? and how can i resolved this
Related
I am using Entity Framework code first with a generic repository pattern with ASP.NET MVC. I have two tables Category and Product.
My model class of product is like this
Public class Product
{
public int ProductID{get;set;}
Public int CategoryID{get;set;}
[ForeignKey("CategoryID")]
public virtual Category Category{get;set;}
[NotMapped]
public string CategoryName{get;set;}
}
The model is binding correctly as long as I am getting data using DBContext.
But I am having a problem when I am getting list of products from stored procedure mapped to Product object. So it is not mapping the Category property of Product object and hence I cannot able to get Category.CategoryName.
So I added a new property with [NotMapped] attribute in product class as CategoryName. But it is also not binding from stored procedure.
And if I remove the [NotMapped] attribute then it is correctly binding from stored procedure but error occurs again when getting product by DbContext (Linq).
Please help me in this regards.
You don't need to add an extra property, use the DbSet.SqlQuery method for queries that return entity types. The returned objects must be of the type expected by the DbSet object, and they are automatically tracked by the database context unless you turn tracking off.
var products= _context.Products.SqlQuery("storedProcedureName",params);
The columns returned by SP should match the properties of your entity type otherwise, it will throw an exception.
After execute your SP, you should be able of get the CategoryName through your Category navigation property:
var catName=someProduct.Category.CategoryName;
On the other hand, the returned data by the Database.SqlQuery isn't tracked by the database context, even if you use this method to retrieve entity types. If you want to track the entities that you get after execute your SP using this method, you can try this:
//Attach the entity to the DbContext
_context.Product.Attach(someProduct);
//The Category navigation property will be lazy loaded
var catName=someProduct.Category.CategoryName;
If you have disabled lazy loading you can load explicitly your navigation property:
//Load the Category navigation property explicitly
_context.Entry(someProduct).Reference(c => c.Category).Load();
I need to update more than one update statements, but all should work on automicity i.e update all or none.
on internet and in someother SO Questions i have found how to use Transaction but i didnt' find any of them saying to update mulitple statements in one transaction.
See below three updates statements, currently there not running under transaction
/// this are my update calls.
var report = reportRepository.Update(reportModel);
var book = bookRepository.Update(bookModel);
var mobile = mobileRepository.Update(mobileModel);
// each Update method for all repository will looks like
public returnModel Update(someModel model)
{
// assign values from model to entity
Context.ObjectStateManager.ChangeObjectState(entity,System.Data.EntityState.Modified)
Context.SaveChanges();
}
You could wrap the updates in a TransactionScope:
using (TransactionScope transaction = new TransactionScope())
{
var report = reportRepository.Update(reportModel);
var book = bookRepository.Update(bookModel);
var mobile = mobileRepository.Update(mobileModel);
...
transaction.Complete();
}
As Darin mentioned use a transaction scope or my preferred method is to have your repositories belong to an IUnitOfWork interface. Calling update simply sets the state to modified and the SaveChanges happens OUTSIDE of your repository to save all changes at once.
This should happen automatically inside of one transaction.
So you call all your Updates and then unitOfWork.SaveChanges where your custom unit of work class contains a reference to your context and implements a method defines in IUnitOfWork called Save()
Basically you need to manage it through TransactionScope Class and using this you can set up multiple update to a Model and then use Transaction.Complete to save your stuff in one transaction.
Please check Updating multiple objects in single transaction in entity framework for more details.
Ok!
I have to say both technology are great. Although there seems that something I do not get it.
You have a data in you database (and let say you want to show data from a table that has references to other tables).
I have a model with List or IEnumerable or IQueryable or whatever...
So in my view I want do foreach through the list of object and take advantage of cool feature of references to other tables. No problem in controller while you are in
using (var datatabse = new MyEntity)
{
}
But when you get out of using db has disposed and you get common error The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
So i do not see other options as creating in memory copies of entity objects...but you loose all cool EF4 references and you have to manually load data first in your model and then with foreach show it on the view.
So instead of List<(EF4Type)> or IEnumerable<(EF4Type)> or IQueryable<(EF4Type)>
you have to do List<(MyCustomHelperClass)> where MyCustomHelperClass represents a class with properties similiar to entity objects and probably some additional beacuse you do not have access to properties of referenced tables Then you have to do foreach and Load data into this List and the another #foreach on the view with Razor to show all.
Twice as much work and if project is big...you can see a bigger picture of how manny those helperClasses you need. Was all this cool new technology really meant to be used in that way?....or am I missing something.
You are probably getting that error when you reference a lazy loaded property in your view. You should eager load everything you need in the Controller before passing it to the View.
See Loading Related Objects (Entity Framework).
The following example will cause all courses to be retrieved with the departments in the same query. This is eager loading.
// Load all departments and related courses
var departments1 = context.Departments
.Include(d => d.Courses)
.ToList();
Without the Include() part, courses could be retrieved later (possibly after your context has been disposed in the view). This is called lazy loading.
Along with eager loading as remembered by jrummell, there's also another way of loading related entries, it's explicit loading. Let's suppose you have a User entity, with many Groups entities related to it. You can explicitly load them:
var user = context.Users.Find(id); // Load the user.
context.Entry(user)
.Collection(u => u.Groups)
.Load();
This way you don't have to use the .Include(), and you can even filter the Groups:
context.Entry(user)
.Collection(u => u.Groups)
.Query()
.Where(g => g.SomeProperty.Contains("something"))
.Load();
TheMentor,
Depending on whether you have a repository or a db context, this object should only live for the duration of the controller action (Request), so you should be able to do everything required within the confines of the action.
Maybe i've misunderstood, but based on your question, this is what your issue appears to be. If I have misunderstood, then I'd still suggest that the db repository or db context should be referenced across the controller, rather then invoking it inside the action each time.
so you should see something like this in your controller:
public class TasksController : BaseController
{
private readonly TaskService _serviceTasks;
public TasksController(IRepository repository)
{
_serviceTasks = new TaskService(repository);
}
//
// GET: /Tasks/
public ActionResult Index()
{
var viewModel = _serviceTasks.All<Task>();
return View(viewModel);
}
public ActionResult Details(int id)
{
var domainModel = _serviceTasks.GetById<Task>(id);
var viewModel = PopulateDetailsViewModel(domainModel);
return View(viewModel);
}
//.. rest of actions cut
}
I'm using MVC3 with EF (version 4, but not sure if 4.0,4.1,etc). I've been fighting with this since yesterday and I don't find the answer anywhere. I'm using the book "Pro Entity Framework 4.0".
I did Model First approach and because I want to use inheritance I created a basic model to do the first testings (sorry, click the link, I don't have enough rep to put a picture):
EF Model
Then with this model I created the database. I'm not very happy with the naming convention, because in spite of pluralizing the entity names, for the derived class table it created a prefixed-single table name. I'm sorry I don't have SSMS installed but have a look through the Server Explorer, see the picture:
DB created from EF Model
Then I created controllers for BaseClass with the template "Controller with read/write actions and views, using Entity Framework". It works great! It created all the views, CRUD.
For instance in the Details view I have this code:
//
// GET: /BaseClass/Details/5
public ViewResult Details(int id)
{
BaseClass baseclass = db.BaseClasses.Single(b => b.Id == id);
return View(baseclass);
}
It works fine.
Then I did the same for the DerivedClass and I got the controller with all the CRUD actions and the views. And now the problem. For instance the Details controller of the DerivedClass is like this:
//
// GET: /DerivedClass/Details/5
public ViewResult Details(int id)
{
DerivedClass derivedclass = db.BaseClasses.Single(d => d.Id == id);
return View(derivedclass);
}
As you can see it tries to get db.BaseClasses instead of db.DerivedClasses, with gives a compilation error, but db does not provide any access to the DerivedClass entity, there is nothing in db at all related with DerivedClass.But if I create manually an instance of DerivedClass in the code it is possible:
MyNamespace.Blablabla.Site.Models.DerivedClass dev = new Models.DerivedClass();
Am I missing anything? Thanks in advance.
Inheritance hierarchies are mapped to one DbSet. If you want to filter on inherited entities you can use:
DerivedClass derivedclass = db.BaseClasses.OfType<DerivedClass>().Single(d => d.Id == id);
The OfType<>() filters the object set for instances of the type you specify.
For adding and updating a derived entity you can also the parent DbSet and EF will map it to the correct tables.
I'm using Subsonic 3 and Automapper on an asp.net MVC3 project.
In my HttpPost ActionResult, I'm taking my model and mapping it to my Subsonic generated entity.
The mapping works no probs, but I can't update the entity.
Upon further inspection, it is because I have no dirty columns, therefore my call to Update() fails as Subsonic doesn't think it needs to update anything.
I've re-jigged the code loads - even forcing the method to load the entity from the db again before mapping against the model. It just seems that the mapping destroys the dirtyColumns tracking. E.g. if I map after loading from the DB, and then change a random property, it doesn't get marked as a dirty column.
I've also tried using the SetIsLoaded(true) method call. No joy after mapping.
Here's my method:
[HttpPost]
public virtual ActionResult Edit(SinglePersonModel model)
{
if (ModelState.IsValid)
{
Data.Person person;
//Now Map my model to my entity - this works
Mapper.CreateMap<SinglePersonModel, Data.Person>();
person = Mapper.Map<SinglePersonModel, Data.Person>(model);
//THIS DOESN'T SET MY COLUMN TO DIRTY
person.Link = "asdjsadij";
//THIS DOESN'T SET MY COLUMN TO DIRTY EITHER
person.SetIsLoaded(true);
person.Link = "asdjsadij";
if (person.PersonId > 0)
PersonRepository.UpdatePerson(person);
else
PersonRepository.CreatePerson(person);
return RedirectToAction(MVC.SecureAdministration.Person.Index());
}
else return View(model);
}
The Static methods on my PersonRepository just call subsonic's Update() and Save() respectively.
Any ideas would be much appreciated. I'm now thinking that I may need to put some additional properties into my model to make sure that they get carried over into the entity by the automapper.
In the worst case I'll have to just not use the Automapper when mapping back to entities from the model, which would suck.
AutoMapper.Mapper.Map<SinglePersonModel, Data.Person>(model, person); - Have you tried it like this? This doesn't assign a new instance of the object but assigns it to the existing object. Just a thought. I understand the want of not loading it from the db. But figured this might help a bit :)
Thanks for that - glad to help out :)