Populating a Lazy<T> collection - asp.net-mvc

I am trying to get my head around lazy loading in an ASP.Net MVC app. For instance, I have a class with a property that is a collection (Employees). I want the collection to only load when I need it loaded:
public class Department
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
[ForeignKey("DepartmentId")]
public Lazy<ICollection<Employee>> Employees { get; set; }
}
First, I am not sure if I should lazy load the class or the collection
public Lazy<ICollection<Employee>> Employees { get; set; }
public ICollection<Lazy<Employee>> Employees { get; set; }
I assume the collection.
Next, I cannot seem to find a related example to actually load the property/collection once I need it and after the class has been instantiated. I am also not sure if this is done in the class itself or in my MVC controller.
Any help is appreciated.

You don't have to use the Lazy<T> on your Employees property. You'll just be adding unnecessary "lazyness", since Entity Framework (and other ORMs like NHibernate) queries are already lazy, i.e.: the query will only hit the database when you explicitly tell it to.
So, by making Employees of type:
public virtual ICollection<Employee> Employees { get; set; } //make sure to mark it as virtual, otherwise it won't be lazy
When querying:
var result = myContextObj.Departments.Include(d=> d.Employees).Where(d=> d.Id == someID).SelectMany(d=> d.Employees);
The code above does nothing but create a Query Object representing the query that may be sent to the database.But it's not going to do anything, unless you "materialize" the result, either by doing a foreach on result, or calling ToList() for example.

For lazy loading you must:
public virtual ICollection<Lazy<Employee>> Employees { get; set; }. You actually miss the virtual that allows the framework to create the proxy by overwritting the property;
context.Configuration.ProxyCreationEnabled = true;, this is the defautl value.

Related

Are child objects supposed to update automatically in Entity Framework 4 Code-First?

I've got this Venue object:
public class Venue
{
public int Id { get; set; }
[Required]
[MaxLength(512)]
public string Name { get; set; }
public string Description { get; set; }
[Required]
[Display(Name = "Venue Type")]
public int VenueTypeId { get; set; }
public virtual VenueType VenueType { get; set; }
[Required]
[Display(Name = "Company")]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
As you can see, it has a collection of VenueParts. I send the Venue to the view, and output the collection of VenueParts as a table of textboxes. This gets posted back to Edit(VenueDetailsViewModel venueDetailsViewModel). Using the debugger, I can verify that my change are in the VenueParts collection, so I think we're good on binding.
My controller tries to update the Venue. It succeeds on the properties directly on the object, such as Name. But, unless I loop through the collection, it does not update those objects. Is that typical behavior?
unitOfWork.VenueRepository.Update(venueDetailsViewModel.Venue);
// Should this loop be necessary?
foreach (var venuePart in venueDetailsViewModel.Venue.VenueParts)
{
unitOfWork.VenuePartRepository.Update(venuePart);
}
unitOfWork.Save();
At the moment, I'm not even worried about handling new stuff in the list or things that vanished from the list (although that is what I am tackling next). For my first step here, I just want to get the list updated. Is it necessary to loop through the collection and update each individual object? If I don't do this, they don't save. But it seems like they ought to without my loop. Are my expectations too high or am I doing something wrong?
My repository and unitOfWork objects are patterned after this tutorial if you are curious what that code looks like.
That is because unitOfWork.VenueRepository.Update(venueDetailsViewModel.Venue); will attach the object graph in Unchanged state and only change the venue as Modified. One alternative would be to move the foreach loop to the VenuePartRepository.Update method.
If you allow elements of VenueParts to be added or removed from the UI you will have a hard time applying the changes. If this is the case you will have to load the collection in the database and compare that with the changes coming in. Then manually change the states of VenuePart to Added or Deleted.

Establish Foreign Key Connection Using Entity Framework With SQL Queries

I have a couple of classes (for this example anyway) that use code first with the entity framework to connect to the database.
public class Customer
{
[Key]
public long CustomerId { get; set; }
public string CompanyName { get; set; }
...
public virtual List<Contact> Contacts { get; set; }
}
public class Contact
{
[Key]
public long ContactId { get; set; }
public string Forename { get; set; }
...
public long CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
When I hook these up in my context class directly to the db the foreign key relationships hook up fine and I can access the collection of contacts from within the customer class.
class RemoteServerContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Contact> Contacts { get; set; }
...
}
My problem is that these database tables are used by various different systems and are massive. In order to increase efficiency I have overridden the default behaviour to point at a view (and also a stored proc elsewhere) rather than directly at the table.
public IEnumerable<Customer> Customers ()
{
return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
}
public IEnumerable<Contact> Contacts()
{
return Database.SqlQuery<Contact>("SELECT * FROM vw_ContactsList");
}
I have made sure that in each of the views I have included the foreign key fields: CustomerId and ContactId.
When I do this however the class joins appear to be lost - there's always a null when I drill into either of the objects where it should be pointing to the other one. I have tried to set up what the foreign key field should point to but this doesn't seem to help either.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>().HasRequired(p => p.Customer)
.WithMany()
.HasForeignKey(k => k.CustomerId);
}
Is there a way to establish the connection when overriding the default behaviour?
There is no overriding in this case. If you removed
public DbSet<Customer> Customers { get; set; }
and replaced it with
public IEnumerable<Customer> Customers ()
{
return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
}
you have completely changed the behavior. The first uses entities and full power of EF. The second is only helper to execute custom SQL. Second without first or without defining entity in OnModelCreating doesn't use Customer as mapped entity at all - it uses it as any normal class (only mapped entities can use features like lazy loading).
Because your Customer is now mapped to view you cannot use your former Customer class used with table. You must define mapping of Customer to a view by cheating EF:
modelBuilder.Entity<Customer>().ToTable("vw_ContactsList"); // EF code fist has no view mapping
Once you have this you can try again using:
public DbSet<Customer> Customers { get; set; }
Unless your view is updatable you will get exception each time you try to add, update or delete any customer in this set. After mapping relation between Customer and Contact mapped to views your navigation properties should hopefully work.
The problem with SqlQuery is the way how it works. It returns detached entities. Detached entities are not connected to the context and they will not lazy load its navigation properties. You must manually attach each Customer instance back to context and to do that you again need DbSet.

Confusion between DAL, Service Layer and repositories

Say I have a simple model like these (small part of a pretty large app)
public class EHR : IEntity
{
public int ID { get; set; }
public string UserName { get; set; }
public DateTime CreationDate { get; set; }
public virtual ICollection<PhysicalTest> PhysicalTests { get; set; }
}
public class PhysicalTest : IEntity
{
public int ID { get; set; }
public virtual EHR Ehr { get; set; }
public Boolean IsDeleted { get; set; }
}
And i want for an easy way to get the physicalTests that are NOT deleted for a given EHR.
So, I can think of three ways of doing this.
one is simply adding a method to my EHR class.(it doesnt seem as such a bad idea cause I dont want to suffer from anemic domain model)
public IEnumerable<PhysicalTest> ActivePhysicalTests()
{
return this.PhysicalTests.Where(!m=>m.IsDeleted).ToList();
}
the other one is creating an extension method under a EHRRepositoryExtensions class:
public static class EHRRepositoryExtensions
{
public static IEnumerable<PhysicalTest> Active(this IEnumerable<PhysicalTest> physicalTests)
{
return physicalTests.Where(test => !test.IsDeleted).OrderByDescending(test => test.CreationDate).ToList();
}
}
I also think I could have extended my IRepository to include a method that returns only the physsicalTests that arent deleted.
something like
public class EHRRepository : IRepository<EHR>
{
//TODO: method that returns only the physsicalTests that arent deleted.
}
I am still trying to grasp many concepts on DDD and I want it to be as pure as possible.
Which of this approaches would you recommend?
whats a rule of thumb on topics like this?
Please Help.
The first approach is recommended as EHR is your Aggregate Root and it is the information expert about its physical tests.
Second approach is not relevant as you have already the model and you can add this method to the entity instead.
The third approach would be preferable only if the list of physical tests takes much time to load from the database, still you can utilize lazy loading but if you want to separate the fetching from the domain or you dont use a lazy loading enabled ORM then put it as a query method in the repository

managing lookup in MVC2 and persisting object with Nhibernate

My simplified domain model looks something like this:
public abstract class Entity<IdK>
{
public virtual IdK Code { get; protected set; }
}
public class Contact : Entity
{
public virtual string Name { get; set; }
public virtual Company Company { get; set; }
}
public class Company : Entity
{
public virtual string Name { get; set; }
}
and I've defined a viewmodel:
public ContactViewModel()
{
public Guid Code { get; set; }
public int Version { get; set; }
public string Name { get; set; }
public string Company { get; set; }
public List<SelectListItem> Companies { get; set; }
}
to manage my contacts in a view.
Since I want the user to be able to choose from a list of companies I've added a list of SelectedListItem which will be rendered in my view like this:
<%=Html.ListBoxFor(m => m.Company, (List<System.Web.Mvc.SelectListItem>)Model.Companies)%>
Now, when the user submits my form I remap my viewmodel with my model before I save it.
I populate my Contact and use the id of the ContactViewModel.Company to create an object of type Company to associate with the property of the Contact class.
Since I don't want to fetch the whole company from the database I just fill the id.
When I persist my contact, though, I get an exception: "not-null property references a null or transient Domain.Contact.Company".
What is the best solution to manage lookups and persistence with MVC + Nhibernate?
Do you have any suggestions from your experience?
Unfortunately with NHibernate and lookups you can't just assign the ID property to a new instance of the Company object and then assign that Company object to the Contact.
Generally what I would do is in my repository, assuming that you can't change the Company information when saving a contact is something like this:
public Contact Save(Contact contact)
{
if(contact.Company.Id > 0)
contact.Company = Session.Load<Company>(contact.Company.Id);
Session.SaveOrUpdate(contact);
}
I generally find this allows you to encapsulate the logic of loading the Company and also allows you to keep it all wrapped up nicely in a single session.
Using Session.Load in this manner avoids hitting the database as described here
If you don't do this, what you're essentially saying to NHibernate is that you have a company object which you have assigned an ID and now want to save it with all the properties set to Null or empty string values or whatever and that is not what you want.
Alternatively you could create a Save specific Domain Object that looks like this:
public abstract class Entity<IdK>
{
public virtual IdK Code { get; protected set; }
}
public class SavableContact : Entity
{
public virtual string Name { get; set; }
public virtual IdK CompanyId { get; set; }
}
Which maps directly to the Contact table in your database so that when you Save this entity you can literally just map back the CompanyId from your view model and NHibernate will only save that value back and not care at all about the company objects.
It's a case of working out what works best for you. I personally prefer the first option as the extra bit of logic helps simplify the domain model, however if you're creating and exposing a public API then the second method might make more sense.

MVC and EF4 CTP model-binding and saving hierarchical model

Am having trouble finding a clear answer to my situation when searching Stack Overflow and Google, hopefully someone can point me in the right direction.
My Situation
I want to be able to use a single edit form (in a single View) to update a 3-level-deep hierarchical entity using ASP.NET MVC 3 and Entity Framework 4 CTP (Code-first) - the model consists of Services, which can have many Service Options, which in Turn can have many Inventory Items.
I was expecting to be able to use MVCs default model binder (via TryUpdateModel) to:
Update an existing 'Service' record
Add/Update/Delete 'Service Option' records (attached to the Service) depending on posted values
Add/Update/Delete 'Inventory' records (attached to each Service Option) depending on posted values
My Model
[Bind(Include="Name, ServiceOptions")]
public class Service {
[Key]
public int ServiceID { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
public virtual ICollection<ServiceOption> ServiceOptions { get; set; }
}
[Bind(Include="ServiceOptionID, Description, Tags")]
public class ServiceOption {
[Key]
public int ServiceOptionID { get; set; }
public int ServiceID { get; set; } /* parent id reference */
public string Description { get; set; }
public virtual ICollection<Inventory> InventoryItems { get; set; }
}
[Bind(Include = "InventoryID, Description")]
public class Inventory {
[Key]
public int InventoryID { get; set; }
public int ServiceOptionID { get; set; } /* parent id reference */
public string Description { get; set; }
}
Ideal Controller Method:
[HttpPost]
public ActionResult EditService(int id) {
Service service = db.Services.Single(s => s.ServiceID == id);
TryUpdateModel(service); // automatically updates child and grandchild records
if (ModelState.IsValid) {
db.SaveChanges();
return RedirectToAction("Index");
}
return View(service);
}
Is there a way to achieve this utopian dream, or am I barking up the wrong tree? I'm open to using another technology (such as normal EF4, Automapper etc)
Thanks in advance!
With just the default model binder? Probably not.
With a custom one? Probably.
However your issue won't be the model binder itself. Your issue will be that EF and ORMs and ( I think ) in general do not consider removing an item from a collection as a delete operation. In effect what you are telling the ORM is the relationship does not exist, not that a child row needs to be deleted. Depending on your mappings you'll usually get an error like "A referential integrity constraint violation occurred". This won't be because of code first this is just how EF works.
EF works this way by design and is really important for more complex relationships such as when you have m2m relationships which reference other m2m relationships. You really want EF to be able to disambiguate calls for removal of a relationship and calls to remove a row entirely.
Also, IMHO, this technique is also bad because your letting the piece of code responsible for mapping http values also dictate how objects should be persisted. This is a bad move. I consider delete operations a pretty sacrosanct act and shouldn't be left to the ModelBinder alone. Without soft deletes or logging deleting objects should be considered "serious business".

Resources