This is my first post :) I'm new to MVC .NET. And have some questions in regards to Entity Framework functionality and performance. Questions inline...
class StudentContext : DbContext
{
public StudentContext() : base("myconnectionstring") {};
public DbSet<Student> Students {get; set; }
...
}
Question: Does DbSet read all the records from the database Student table, and store it in collection Students (i.e. in memory)? Or does it simply hold a connection to this table, and (record) fetches are done at the time SQL is executed against the database?
For the following:
private StudentContext db = new StudentContext();
Student astudent = db.Students.Find(id);
or
var astudent = from s in db.Students
where s.StudentID == id)
select s;
Question: Which of these are better for performance? I'm not sure how the Find method works under-the-hood for a collection?
Question: When are database connections closed? During the Dispose() method call?
If so, should I call the Dispose() method for a class that has the database context instance? I've read here to use Using blocks.
I'm guessing for a Controller class get's instantiated, does work including database access, calls it's associated View, and then (the Controller) gets out of scope and is unloaded from memory. Or the garbase collector. But best call Dispose() to do cleanup explicitly.
The Find method looks in the DbContext for an entity which has the specified key(s). If there is no matching entity already loaded, the DbContext will makes a SELECT TOP 1 query to get the entity.
Running db.Students.Where(s => s.StudentID == id) will get you a sequence containing all the entities returned from a SQL query similar to SELECT * FROM Students WHERE StudentID = #id. That should be pretty fast; you can speed it up by using db.Students.FirstOrDefault(s => s.StudentID == id), which adds a TOP 1 to the SQL query.
Using Find is more efficient if you're loading the same entity more than once from the same DbContext. Other than that Find and FirstOrDefault are pretty much equivalent.
In neither case does the context load the entire table, nor does it hold open a connection. I believe the DbContext holds a connection until the DbContext is disposed, but it opens and closes the connection on demand when it needs to resolve a query.
Related
I'm learning Entity Framework Core. I came across the term "Owned Entity" in almost all tutorials.
Here is one example on using an Owned Entity in Entity Framework Core
Job Entity:
public class Job : Entity
{
public HiringManagerName HiringManagerName { get; private set; }
}
HiringManagerName Value Object:
public class HiringManagerName : ValueObject
{
public string First { get; }
public string Last { get; }
protected HiringManagerName()
{
}
private HiringManagerName(string first, string last)
: this()
{
First = first;
Last = last;
}
public static Result<HiringManagerName> Create(string firstName, string lastName)
{
if (string.IsNullOrWhiteSpace(firstName))
return Result.Failure<HiringManagerName>("First name should not be empty");
if (string.IsNullOrWhiteSpace(lastName))
return Result.Failure<HiringManagerName>("Last name should not be empty");
firstName = firstName.Trim();
lastName = lastName.Trim();
if (firstName.Length > 200)
return Result.Failure<HiringManagerName>("First name is too long");
if (lastName.Length > 200)
return Result.Failure<HiringManagerName>("Last name is too long");
return Result.Success(new HiringManagerName(firstName, lastName));
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return First;
yield return Last;
}
}
Entity Configuration:
public class JobConfiguration : IEntityTypeConfiguration<Job>
{
public void Configure(EntityTypeBuilder<Job> builder)
{
builder.OwnsOne(p => p.HiringManagerName, p =>
{
p.Property(pp => pp.First)
.IsRequired()
.HasColumnName("HiringManagerFirstName")
.HasMaxLength(200);
p.Property(pp => pp.Last)
.IsRequired()
.HasColumnName("HiringManagerLastName")
.HasMaxLength(200);
});
}
}
And this gets created as two columns in table like other columns in Job Entity.
Since this is also created as columns just like other properties in entity this can directly be added as normal properties in the Job Entity. Why this needs to be added as Owned Entity?
Please can anyone help me understand,
What is owned entity?
Why we need to use owned entity?
When to use owned entity?
What does this look like without owned entities?
If you create an entity, Job, in EF Core that points to a complex object, HiringManagerName, in one of the properties, EF Core will expect that each will reside in a separate table and will expect you to define some sort of relationship between them (e.g. one-to-one, one-to-many, etc.).
When retrieving Job, if you want to explicitly load the values of HiringManagerName as well, you'd have to use an explicit Include statement in the query or it will not be populated.
var a = dbContext.Jobs
.Include(b => b.HiringManagerName) //Necessary to populate
.ToListAsync();
But because each is thought to be a separate entity, they will be required to expose keys and you'll have to configure foreign keys between each.
What is an owned entity?
That's where [Owned] types come in (see docs). By marking the child class with the [Owned] attribute, you leave the explicit handling of that relationship to EF Core to manage and no longer have a need to define the key(s)/foreign key(s) on the owned type. Same if you point to a collection of your owned type - you no longer need to deal with navigation properties on either class to describe the relationship.
EF Core also supports queries against these owned types, as in:
var job = context.Jobs.Where(a => a.HiringManagerName.First == "fingers10").FirstOrDefaultAsync();
Now, it comes with two important design restrictions described in the docs (but elaborated on here):
You cannot create a DbSet for the owned type
This means that you cannot subsequently do a DB call with:
dbContext.HiringManagerNames.ToListAsync();
This will throw because you are expected to simply retrieve the value as part of a call to:
dbContext.Jobs.ToListAsync();
Unlike the first example I gave, HiringManagerNames no longer needs to be explicitly included and will instead be returned with a call to the Jobs DbSet<T>.
Cannot call Entity<T> with an owned type on ModelBuilder
Similarly, you cannot reference your owned type in the ModelBuilder to configure it. Rather, if you must configure it, do so through the configuration against your Jobs entity and against the owned property, e.g.:
modelBuilder.Entity<Job>().OwnsOne(a => a.HiringManagerNames).//Remaining configuration
So when should I use owned entities?
If you've got a type that's only ever going to appear as a navigation property of another type (e.g. you're never querying against it itself as the root entity of the query), use owned types in order to save yourself some relationship boilerplate.
If you ever anticipate querying the child entity independent of the parent, don't make it owned - it will need to be defined with its own DbSet<T> in order to be called from the context.
While #Whit Waldo explanation is great with respect to technical ef core, we should also try to understand from Domain Driven Design perspective.
Lets observe the classes mentioned in the question itself
public class Job : Entity
and
public class HiringManagerName : ValueObject
Take a note at Entity and ValueObject. Both of them are DDD concepts.
Identity matters for entities, but does not matter for value objects.
Take a look at this write up from Vladimir Khorikov for a more extensive explanation.
I past the summary bullets here.
Entities have their own intrinsic identity, value objects don’t.
The notion of identity equality refers to entities; the notion of structural equality refers to value objects; the notion of reference equality refers to both.
Entities have a history; value objects have a zero lifespan.
A value object should always belong to one or several entities, it can’t live by its own.
Value objects should be immutable; entities are almost always mutable.
To recognize a value object in your domain model, mentally replace it with an integer.
Value objects shouldn’t have their own tables in the database.
Always prefer value objects over entities in your domain model.
So a value object is owned by an entity. So how do we achieve that using EF Core? Here comes the concept of Owned entities. Now go back and read #Whit Waldo answer.
I have an application in which I verify the following behavior: the first requests after a long period of inactivity take a long time, and timeout sometimes.
Is it possible to control how the entity framework manages dispose of the objects? Is it possible mark some Entities to never be disposed?
...in order to avoid/improve the warmup time?
Regards,
The reasons that similar queries will have an improved response time are manifold.
Most Database Management Systems cache parts of the fetched data, so that similar queries in the near future will be faster. If you do query Teachers with their Students, then the Teachers table will be joined with the Students table. This join result is quite often cached for a while. The next query for Teachers with their Students will reuse this join result and thus become faster
DbContext caches queried object. If you select a Single teacher, or Find one, it is kept in local memory. This is to be able to detect which items are changed when you call SaveChanges. If you Find the same Teacher again, this query will be faster. I'm not sure if the same happens if you query 1000 Teachers.
When you create a DbContext object, the initializer is checked to see if the model has been changed or not.
So it might seem wise not to Dispose() a created DbContext, yet you see that most people keep the DbContext alive for a fairly short time:
using (var dbContext = new MyDbContext(...))
{
var fetchedTeacher = dbContext.Teachers
.Where(teacher => teacher.Id = ...)
.Select(teacher => new
{
Id = teacher.Id,
Name = teacher.Name,
Students = teacher.Students.ToList(),
})
.FirstOrDefault();
return fetchedTeacher;
}
// DbContext is Disposed()
At first glance it would seem that it would be better to keep the DbContext alive. If someone asks for the same Teacher, the DbContext wouldn't have to ask the database for it, it could return the local Teacher..
However, keeping a DbContext alive might cause that you get the wrong data. If someone else changes the Teacher between your first and second query for this Teacher, you would get the old Teacher data.
Hence it is wise to keep the life time of a DbContext as short as possible.
Is there nothing I can do to improve the speed of the first query?
Yes you can!
One of the first things you could do is to set the initialize of your database such that it doesn't check the existence and model of the database. Of course you can only do this when you are fairly sure that your database exists and hasn't changed.
// constructor; disables initializer
public SchoolDBContext() : base(...)
{
//Disable initializer
Database.SetInitializer<SchoolDBContext>(null);
}
Another thing could be, if you already have fetched your object to update the database, and you are sure that no one else changed the object, you can Attach it, instead of fetching it again, as is shown in this question
Normal usage:
// update the name of the teacher with teacherId
void ChangeTeacherName(int teacherId, string name)
{
using (var dbContext = new SchoolContext(...))
{
// fetch the teacher, change the name and save
Teacher fetchedTeacher = dbContext.Teachers.Find(teacherId);
fetchedTeader.Name = name;
dbContext.SaveChanges();
}
}
Using Attach to update an earlier fetched Teacher:
void ChangeTeacherName (Teacher teacher, string name)
{
using (var dbContext = new SchoolContext(...))
{
dbContext.Teachers.Attach(teacher);
dbContext.Entry(teacher).Property(t => t.Name).IsModified = true;
dbContext.SaveChanges();
}
}
Using this method doesn't require to fetch the Teacher again. During SaveChanges the value of IsModified of all properties of all Attached items is checked. If needed they will be updated.
I've got a simple GET method in my Web API 2 project which queries my Microsof tSQL database via Entity Framework that always returns an error. If I step through it in the debugger the exception is NOT hit. It actually looks like it's cleanly leaving the method. I'm very confused.
[Route("ar")]
public IHttpActionResult GetAuditArs(int auditId)
{
using (var context = new LabSOREntities()) {
try {
var ars = from r in context.SMBWA_Audit_AR
where r.SMBWA_Audit_Id == auditId
select r;
var ret = Ok(ars.ToArray());
return ret;
} catch (Exception ex) {
return BadRequest($"Something went wrong: {ex.Message}");
}
}
}
There's one row in the database, and I see my ars.ToArray() says that's there's a single element in it. How can I debug this since it's left my method when it blows up?
If I just hit that endpoint via the browser I get:
<Error>
<Message>An error has occurred.</Message>
</Error>
The issue will be that you are returning entities from your API call. Behind the scenes WebAPI has to serialize the data being returned, as it does this it will hit any lazy-load reference properties and attempt to load them. Since you are instantiating a scoped DB Context within a using block, the entities will be orphaned from the context prior to the serialization so EF will be throwing exceptions that the DB Context is not available.
Option to verify the behaviour
- Eager-load all references in your "SMBWA_Audit_AR" class. This should eliminate the error and confirm the lazy load serialization issue.
var ars = context.SMBWA_Audit_AR
.Include(x => x.Reference1)
.Include(x => x.Reference2) // etc. where Reference1/2 are related entites to your audit record. If you have a lot of references, that is a lot of includes...
.Where(x => x.SMBWA_Audit_Id = auditId)
.ToArray();
To avoid issues like this, and the cost/time to eager-load everything I recommend using a POCO DTO/ViewModel to return the details about these audit records. Then you can .Select() the fields needed for the POCO. This avoids the lazy-load serialization issue, plus optimizes your queries from EF to return just the data that is needed, not the entire object graph.
for example:
If you need the Audit #, Name, and a Notes field to display in a list of audit summaries:
public class AuditSummary
{
public int AuditID {get; set;}
public string AuditorName {get; set;}
public string Notes {get; set;}
// You can add whatever fields are needed from the Audit or related entities... Including collections of other DTOs for related entites, or summary details like Counts etc..
}
var ars = context.SMBWA_Audit_AR
.Where(x => x.SMBWA_Audit_Id = auditId)
.Select(x => new AuditSummary
{
AuditId = x.AuditId,
AuditorName = x.AuditedBy.Name, //Example getting reference details..
Notes = x.Notes
}).ToArray();
Return models that reflect what the consumer will need. This avoids issues with EF and ensures your queries are efficient.
Scope the DbContext to the Request using an IoC Container (Unity/Autofac, etc.) This can seem like a viable option but it isn't recommended. While it will avoid the error, as the serializer iterates over your entity, your DbContext will be querying each individual dependency one at a time by ID. You can see this behaviour by running a profiler against the database while the application is running to detect lazy-load calls. It will work in the end, but it will be quite slow.
As a general rule, don't return entities from Web API or MVC controller methods to avoid errors and performance issues with serializers.
I have a web application (MVC 5, EntityFramework 6). It's connected to an SQL database via a DbContext. I'm having an issue where adding a new entity object creates a duplicate entry in the entity set (but not the DB) and I'm not sure how to stop this from happening.
Controller, whose method is called via an ajax request:
public class CustomerController : Controller
{
MyDBEntities db = new MyDBEntities(); //DbContext
public ActionResult SaveStuff(string customerId, string stuff)
{
Customer customer = db.Single(c => c.ID.Equals(customerId));
Stuff stuff = new Stuff(stuff, customer);
db.Stuffs.Add(stuff);
db.SaveChanges();
return PartialView("MyControl", customer);
}
}
There is a 1-to-many association between Customer and Stuff, and there is a "Stuffs" navigation property in Customer.
Stuff includes fields that are int, string, and DateTime.
The controller method returns a PartialView which is used by JavaScript to refresh the contents of a control.
The "MyControl" control does this:
var stuffs = Model.Stuffs.OrderByDescending(...);
When the control is rendered in this situation, Model.Stuffs contains a duplicate entry. There's an entry with a name of Stuff (probably the new object created in the control method) as well as well as an entry with a name of System.Data.Entity.DynamicProxies.Stuff_<uuid> which is the same exact data (I imagine read from the DB).
This is only a problem when I'm writing into and then reading from an entity set within the same web request. Other/future web requests that cause a read are fine. How can I make this work correctly?
This is happening because the DateTime object is losing precision when it is written into the SQL database (see: SQL Server DateTime vs .NET DateTime). When read back from the DB, it has a different value and therefore does not overwrite the existing "stuff" object that still exists locally in db.Stuffs.
A simple solution is to change the DateTime's setter for Stuff to private and add your own pseudo-setter function that has the rounding built into it:
public void SetTimestamp(DateTime timestamp)
{
//Precision in SQL is lower than in .NET, so just round to tenth seconds
this.Updated = timestamp.AddTicks(- (timestamp.Ticks % (TimeSpan.TicksPerSecond / 10)));
}
Using DateTime2 in the SQL database (Server 2008+) is also an option should you need to maintain that level of precision.
I am working with Entity Framework ... I have a database table for Patient which has a non-enforced foreign key relationship to the Employee table so I can associate a manager to a patient.
I created my entity in EF for the Patient, the Employee and an association between Patient and Employee, which I name to ManagerEmployee.
I also created another partial class for Patient that will allow me to easily get at the name of the employee from my business object class, also called Patient.
public string ManagerName
{
get { return this.ManagerEmployee == null ? string.Empty : this.ManagerEmployee.Name; }
}
So I have:
Patient Entity
Patient Partial Class
(to help with some of the data
retrieval)
Patient DTO (reads from
the Patient Entity)
The problem that I am having is that if the ManagerId (in this case is a Guid) does not related to an employee, or is not set (Guid.Empty) ... even though I am eager loading, it still makes another hit on the database.
IQueryable<Data.Patient> query = ctx.ObjectContext.Patients.Include("ManagerEmployee");
So if I have a 1000 records, that have this value set, all is well, but if the value for ManagerId is NOT set on any of these records, it makes 1+1000 database hits.
Wondering if anyone else has had this problem? There may be some bigger problem with the construction of my EF entities and/or associations, so I'm open to other suggestions.
Thanks!
This is now pretty old but in case you haven't already found the solution, my suggestion is to turn off lazy loading. What is most likely happening is that when you try to access a property that is null, lazy loading is happening. See
http://www.asp.net/entity-framework/tutorials/maximizing-performance-with-the-entity-framework-in-an-asp-net-web-application
if you're using database first, or
http://www.asp.net/entity-framework/tutorials/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
for MVC Code First.