Does instantiating a DbContext From EF read the whole database? - asp.net-mvc-3

When instantiating EntityFramework's DbContext in MVC3, does the whole database get read? When debugging, it is possible to access all of the data in the entire database by looking at the instantiated DbContext so wouldn't this imply that all the data is grabbed when the first connection is made?

No definitly not. The data is loaded, when you access the DbSet/ObjectSet properties of your DbContext.
Only the data you query for is loaded from the db and mapped to objects. For example, when you query like
DbContext.Table.Where(row => row.Prop1 == "Value")
Its translated to SQL, evaluated at the database and only the rows that match your query are returned to your app.

No, the entire database is not read on instantiation. The entity collections (DbSet<>) in your DbContext are lazy evaluated. So when you're debugging and navigate into one, it's being queried then, not when the DbContext instance is instantiated.

No, Entity Framework tries to only query the database when you need information, or you need to modify information.
The following example is my personal interpretation of what I think EF is doing behind the scenes. It's probably somewhat inaccurate, but serves a point for illustration purposes.
using(var db = new MyDbContext()) // 1
{
var entities = db.MyEntities; // 2
foreach(var entity in entities) // 3
{
// 4
} // 5
} // 6
Establish connection with database
Get some object representing a query that says "Get me all dem entities."
Enumerate the object. Aka, have the context's query provider translate "get me all dem entites" to (assuming sql) "select * from MyEntity with (nolock);", and run the query returning an ADO.NET SqlDataReader, which will read the first row, map the object into an (optionally) lazy object with some metadata, so EF knows what row it's mapped to, etc, and yeild that as the "entity" variable.
Do something with the entity you magically received from the database without actually doing any real work (thank Entity Framework!)
Ask EF to move the SqlDataReader to the next row and yield another entity (aka, go back to step 3, but only if another row exists)
Close the connection with the database.

Related

Does Entity Framework automatically load all of my data (not a reference and lazy load is off)?

I have a database first Entity Framework project. For every entity that I add, a collection is added to the DbContext for the entity. I explicity set LazyLoadingEnabled = false in the DbContext constructor. If I break into the following code and check the count of CustomerDepartments, I get the total count of the table. If I'm just adding a new record, I expect the count to be 0 before I add, and 1 after. I'm using this in a stateless environment, so loading the whole table just to add a record seems absurd. What am I doing wrong?
using (Model.SupportEntities support = new Model.SupportEntities(_state.Credentials, _handler.ReadWriteConnectionString))
{
Model.CustomerDepartment department = Json.JsonConvert.DeserializeObject<Model.CustomerDepartment>(_insertObject);
support.CustomerDepartments.Add(department);
support.SaveChanges();
_state.ReturnNewIdAsJson(department.CustomerDepartmentID);
}
It seems you have misinterpreted how DbContext and DbSet works.
It maybe best if you get hold of a tool for logging EntityFramework SQL calls try Clutch.Diagnostics.EntityFramework.
When you call IEnumerable<T>.Count() on DbSet<T>, Entity Framework runs the following query
SELECT COUNT(*) FROM TableName;
But it does not load the whole table.
The ACTUAL call you want for the behavior you wanted was either
support.CustomerDepartments.Local.Count;
OR
support.ChangeTracker.Entries<T>().Count()
These will NOT hit the database.
You have to remember that DbSet is an abstraction for the Database table, so calling Count() on it should tell you how many rows there are in the table.
BTW. FYI. The convention is call name your DbContext to be SupportContext. Model named classes or namespace suggests they are your POCOs.

Replacing EF4.1 with ADO.net when calling stored proc in MVC3?

I need to replace EF4.1 with ADO.NET. The data in our application is returned by stored procedures only. I need help re-writing calls like the following (in order to write a DAL for the application):
EF calling stored procedure:
using (var db = new NexGenContext())
{
SqlParameter param = new SqlParameter("#ReviewID", Id);
var issues = db.Database.SqlQuery<QuestionIssue>(
"SP_GetQuestionIssues #ReviewID", param).ToList();
return View(issues);
}
What is the equivalent in ADO.NET? Get data from the database and map to my models?
The closest ADO.NET technology to being an ORM without actually crossing the line is data sets. Data sets act very much like an ORM in the way you can access data directly from a table without looping through a cursor. Data Sets return lists directly and can track new data vs old.
This link is a pretty good overview:
http://www.c-sharpcorner.com/UploadFile/718fc8/working-with-dataset-in-ado-net/
This MVC datasets with viewbags stack thread specifically addresses using Data Sets in Models.

Partial loading of Entity Framework entities and passing them to presentation layer

If I want to select only few columns when retrieving data for an EF entity and cast them to the Entity type, I am not able to do that because it throws an error as mentioned in this post
The entity cannot be constructed in a LINQ to Entities query. I don't want to select all the columns, because I need only few of them. I can use anonymous types, but if I am using repository pattern and want to encapsulate all data access code in repository object and pass strongly typed object collection to the controller (not an anonymous object collection), how can I achieve that? Is the only option to define a DTO object for every subset of the properties for the EF entity? I know there is a risk of losing data with partial loaded entities, but if I am ready to take the risk and want full control over data updates, is that not possible?
for example I would like the "ProductRepository" method signature to be like this
public IEnumerable<Product> GetProducts(int categoryID) //selection of subset of data
and I want to pass this product collection from the controller to the view (in ASP.NET MVC project) and in the view I want to have strongly typed model (with intellisense) object. Is this possible? if not, I may have to reconsider using EF for my project due to this limitation. I am using EF 4.1 version.
Yes the option in this case is special object for each subset of properties you want to select. You can call the object DTO because it is just a result of the projection. This is the correct approach because if your UI doesn't need other properties of entity type it is correct to pass it only specialized ViewModel.
Another more complex (and worse) option is selecting anonymous type inside your Linq-to-entities query, calling ToList and after that construction the real entity type. Partial entity selection is not allowed and projecting to mapped entity types is not allowed as well. That is the reason why you have to use such a cumbersome approach. Example:
// Select anonymous projection
var query = from x in context.Entities
where ...
select new { ... };
// Repopulate entity type
var reultSet = query.ToList().Select(x => new Entity { ... });
Yes, what you want is totally possible using viewmodels instead of entities. Here is example controller code:
var productEntities = productRepos.GetProducts(6);
var productViewModels = Automapper.Mapper
.Map<IEnumerable<ProductViewModel>>(productEntities);
return View(productViewModels);
Your view model will have only the properties it needs for the view. Check out automapper.

MVC Linq to SQL Update Object in database

I have a table called Code in my LINQ to SQL datacontext. I also have a class called Codes in my Models folder. What I want to do is save the updated object Codes to my database table Code. Is this possible?
In my controller, I would pass the edited Object to my Model. My CodesRepository file contains this:
public Codes EditCode(Codes CodeToEdit)
{
private EventsDataContext _db = new EventsDataContext();
Codes C = new Codes();
C = CodeToEdit;
_db.Codes.InsertOnSubmit(C); //error here, something about invalid arguments
//InsertOnSubmit is for adding a new object, but I don't know the syntax
// for editing an existing object.
_db.SubmitChanges();
}
This is probably not the correct way of doing this so can someone point me in the right direction? Do I even need a class called Codes or do I need to somehow just use my database table? Thanks.
Solution: I decided to change from Linq to SQL to an Entity Framework and it works much better. This way, I don't have to define my Codes class since it comes straight from the database and I was able to delete the Codes class file.
You should use DataContext.Attach when you get an object back that corresponds to en existing row in the database. For Linq-to-sql's optimistic concurrency handling to work this requires that you either have the original, unsaved object available, or that you have a TimeStamp column in the database. The latter is preferred, as it only requires one extra field to be handled (probably through a hidden field in the web form).

How to refresh relational property of a LINQ class?

I have two instances of a program that manipulate same Northwind database.
When I add some records to the database from one of the instances (for example adding some orders to Orders table with a customer foreign key John), I can query these new records from the other instance of the program properly. The problem begins when I want to access these new records using John.Orders. In this situation, the second instance of the program does not see newly added records. What should I do?
The problem you are having is probably related to the time you keep the LINQ to SQL DataContext class alive. It should typically be destroyed after each unit of work you do with it (since it follows the 'unit of work' design pattern), which typically means after each use case / business transaction.
You are probably keeping the DataContext class alive during the entire lifetime of the application. The DataContext class is not suited for this, because it will cache all objects it had once retrieved meaning that your data will get stale.
Create a new DataContext class for every operation or every time the user opens a new form / screen.

Resources