Checking for a null object in EF causes an additional database hit ... how come? - entity-framework

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.

Related

Entity Framework 6 - Form relationship using object which doesn't exist in the DB yet

Suppose a Company has Employees. Company 'Solutions' has Employee 'James'.
These entities are both saved in the DB, and their relationship is expressed through a foreign key.
At the application level, the Employee class has a Company object property, to define the relationship.
Suppose a new company 'Better Solutions' is created, which doesn't exist in the DB yet, and James now moves to this company.
How do I tell EF to handle this? Currently I:
Save the new company 'Better Solutions' (object created with a GUID ID) to the DB:
db.Companies.Add(newCompany);
Change the Company property on Jame's instance:
james.Company = newCompany;
Tell EF that a property on James's instance has changed and needs updating:
db.Employees.Attach(james);
db.Entry(james).State = System.Data.Entity.EntityState.Modified;
But when this happens, the newCompany object doesn't have its new database ID yet (even though it's been added to the database, the object still holds the GUID ID), so when saving EF tries to do this:
UPDATE [dbo].[Employee]
SET [CompanyID] = SomeGUID,
WHERE ([EmployeeID] = JamesID)
Which of course throws an exception because no CompanyID matches that GUID:
The UPDATE statement conflicted with the FOREIGN KEY constraint
In this scenario, do I need to first push the newCompany object to the DB, then retrieve it from the DB (to get the new ID), then set this retrieved object as James's Company property?
Or does EF have a cleaner way of taking care of all this?
try to do like below. Save company first then assign it to james that will update existing employee.
db.Companies.Add(newCompany);
db.SaveChanges();
james.Company = newCompany;
db.SaveChanges();

EF LINQ to Entites query for a Many to Many relationship

trying to work out how to do LINQ to Entities query for a many to many relationship which has a junction with fields table.
Below are the Domains models (I am using View models, but keeping it simple for this example).
Student Domain model
StudentID (PK)
ICollection<StudentCourse> StudentCourses
StudentCourse Domain model
StudentCourseID (PK)
StudentID (FK)
CourseID (FK)
ForAdult
ForSeniour
Description
Course Domain model
CourseID (PK)
ICollection<StudentCourse> StudentCourses
Note:
Since the junction table (i.e. StudentCourse) contains fields other than the two foreign keys, EF will create an entity for this.
Lazy Loading
I've got this working for lazy loading. The Navigation properties have been declared with the 'virtual' keyword.
The Query way - works!
var student = (from s in context.Students
where s.StudentID == id
select s).SingleOrDefault<Student>()
The Method way - works!
Student student = context.Students.Find(id);
Projection
BUT, I would prefer to do this with projection, for performance reasons, i.e. less trips to the database.
I'm really stuck on how to write up the LINQ to Entities query to return 1 student with (1 or) many StudentCourses.
I don't understand thoroughly how the Entity should be shaped, if you know what I mean.
For example, I've tried:
var myvar = from s in context.Students
from sc in s.StudentCourses
where s.StudentID == id
select s
What I require is to return an entity of Student with a collection of StudentCourses which could then be assigned to a Student and passed to the View model, then to the View.
Really would appreciate any help, as I've spent alot of time trying to solve this.
Also as a side note, I'm using the SingleOrDefault() method to cast the results of the var (IQueryable I think) to type Student. Is this the preferred way to cast?
You can get EF to eagerly load the related entities by using the Include method.
So using your LINQ example:
var student = (from s in context.Students
where s.StudentID == id
select s).Include("StudentCourses").FirstOrDefault();
And using extension methods:
var student = context.Students.Include("StudentCourses").FirstOrDefault(id);
The Student instance that is returned will have the StudentCourses collection populated with related entities. This should invoke only one SQL query that joins the tables together.
To answer your aside question: I prefer to use FirstOrDefault most of the time as above. The difference is that SingleOrDefault will expect exactly one result and throws an exception otherwise, whereas FirstOrDefault will return null if a student is not found.
Also, as the cast to Student is implicit, you don't need the <Student> type parameter.

Entity Framework Code First - Table Per Type Inheritance - Insertion Issue?

I'm having an issue inserting an instance of a subclass that inherits from a base class.
Consider the following code snippets from these POCOs:
public abstract class EntityBase<T>
{
private T _id;
[Key]
public T ID
{
// get and set details ommitted.
}
}
public abstract class PersonBase<T> : EntityBase<T>
{
// Details ommited.
}
public class Applicant : PersonBase<int>
{
// Details ommitted for brevity.
}
public class Employee : Applicant {}
Pretty standard inheritance right now. In our system, when an applicant finally becomes an employee, we collect extra data. If not hired, they remain an applicant with a limited set of information.
Now consider the fluent API that sets up the table-per-type inheritance model:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Set up table per type object mapping for the Visitor Hierarchy.
modelBuilder.Entity<Employee>().ToTable("Employees");
}
So far, so good...
If I look at the database this creates, I have a table named Applicants with an Id column of type int, auto-incrementing ID and I have an Employees table with an ID field as the primary key (non auto incrementing).
Basically, the ID field in the Employees table is a foreign key to the Applicants table.
This is what I want. I don't want a record into the Employees table corresponding to the Applicants table until they actually become an Employee.
The problem comes when I try to insert an Employee which comes down to this code:
public void PersistCreationOf(T entity)
{
DataContextFactory.GetDataContext().Set(typeof(T)).Add(entity);
}
The problem: It inserts a brand new applicant and Employee. I hooked it up to the Sql Profiler and looked at both insert queries that come down.
I want to just insert the Employee record with the ID it already has (the foreign key from the Visitors table).
I understand by default it needs to this: Obviously if you create a subclass and insert it, it needs to insert into both tables.
My question is is possible to tell the Framework - the base table already has information - just insert into the child table?
Thanks in advance!
Aside from sending raw SQL commands to insert the Employee minus Applicant properties fragment into the Employees table I believe it's impossible. You can either update or insert an entity. What you want is basically to update the base part of the Employee (or do nothing if nothing changed) and insert the derived part which is not possible.
Imagine what an ORM does: It maps key identities in the database to object identities in memory. Even in memory you couldn't achieve what you want: If you have an object in memory which is a Applicant, it is always an applicant. You cannot magically "upgrade" it to an Employee. You would have to create a new object of type Employee, copy the properties of the Applicant into the base properties of your new Employee and then delete the Applicant. The result is a new object with a new object identity.
I think you have to follow the same procedure in EF. Your Employee will be a new entity with new rows in both Applicant and Employee table and you need to delete the old Applicant. If you have autogenerated keys it will be a new identity with a new ID. (If you hadn't autogenerated keys you could supply the old ID again after deleting the old Applicant, thus "faking" an unchanged identity.) This will of course create big potential trouble if you have references to the old applicant with FK constraints.
Perhaps inheritance is not optimal for this scenario to "upgrade" an applicant into an employee. An optional navigation property (1-to-0...1 relationship) inside of the Applicant which refers to another entity containing the additional properties which make the applicant an employee would solve the problem. This navigation property could be set or not, letting you distinguish between an applicant and applicant which is also an employee. And you would not need to delete and change the ID of the applicant when you make it an employee.
(As said, "I believe". Maybe there is a hidden way, I didn't see.)

ADO.NET Entity Data Model: Auto-generated classes

I have a table structure like the following:
Companies Addresses
********* *********
ID ID
AddressID ...
BillingAddressID ...
AddressID and BillingAddressID are foreign keys which are present in the Addresses table. When I generate my model based on this table instead of getting what I would expect to get (the AddressID, BillingAddressID) in the company class. I get the following:
public Addresses Addresses { .. }
public global::System.Data.Objects.DataClasses.EntityReference<Addresses> AddressesReference { .. }
public Addresses Addresses1 { .. }
public global::System.Data.Objects.DataClasses.EntityReference<Addresses> Addresses1Reference { .. }
It seems to be replacing BillingAddress with Addresses1 (not quite sure why that's happening). Also this seems to be common wherever I have a foreign key i.e. instead of the ID I get Table then the TableReference.
I think I can see whats happening i.e. instead of giving me the ID alone, it will be doing a lookup and finding the actual record the ID refers to. However, I am not quite sure what the TableReference field is for....
Can explain this a little better for me?
Thanks in advance.
Relationships are represented as objects in Entity Framework, in the same manner as entities. Even if you are not going to work a lot directly on them, relationship object are first class citizens in EF. EF kreates ObjectStateEntry objects for tracking changes on relationships, just like it does it for entities.
That is why there are two references. First one, AddressesReference is a reference to the relationship object, not the exact entity, and second one Addresses is actual entity.
Peter Chan (link), and Julia Lerman in her book Programming Entity Framework, 1st Edition, say that understanding how relationship works in EF is very important. Also they mention that this is first thing that is confusing developer when they start using EF.
The foreign keys are replaced by a reference to the entity (collection) the foreign key points to.
So to add an address to a company you would do something like:
Address a = new Address();
// ... set variables for address here
currentCompany.Addresses = a;
// or, the other way round (for collections)
a.Companies.Add(currentCompany);
EF uses the table names as the reference point when it builds the model and this is why you see "Addresses" and Addresses1". You can open up the entity model in the GUI format and click on each of the associations. These can be renamed to whatever you like, just click on the reference, view the mapping, ensure it is the one that maps "BillingAddressID" to "BillingAddressID" and rename that reference to "BillingAddress".
Note the current "Addresses" reference may be the one mapping the "BillingAddressID" so you have to check both references.
It would probably be best to change the mapping for "AddressID" to be "Address" instead of "Addresses" if it is a one to one mapping as well.

Removing an association from an entity

I have 2 entities: User and Company, with a FK from the User to the Company.
I'm trying to remove the association and leave the user entity with a scalar property "CompanyId", but still have the "Company" entity in the model (mainly to increase performance, I don't need to full entity attached to it).
I'm able to achieve that only by removing the association and then go to the edmx (xml) file and remove the leftovers manually, BUT...
After I regenerate the model (following additional changes in the schema etc.), I'm getting the "Company" association once again on the "User" object (along with the "CompanyId" property), which of course causes errors of mappings, since I'm having 2 mappings to the same CompanyId field in the database. Going once again to the xml to fix it is not something I'd like to do...
Is there a way around this? -Taking the "Company" table out to another model is not possible.
Thanks,
Nir.
I think I found the answer.
I can leave the entity association without the scalar property, and set it to a private getter. Then, add to the partial class the following:
public int CompanyId
{
get
{
return
(int)CompanyReference.EntityKey.EntityKeyValues.First(c => c.Key == "Id").Value;
}
}
That way I don't need to go to the database to fetch the company association along with the user, but I still have the value.
Nir.