Automapper and lazy loading with EF and performance - entity-framework

I have a model like this
public class Exam
{
public int NewsId { get; set; }
public string Title { get; set; }
public string Description{ get; set; }
public string Program{ get; set; }
}
and a view model like this
public class ExamViewModel
{
public int NewsId { get; set; }
public string Title { get; set; }
}
and I do config Automapper like this
AutoMapper.Mapper.CreateMap<Exam, ExamViewModel>();
and in an ActionResult I used Automapper like this:
public ActionResult Exam()
{
var examsDb = db.Exams;
IEnumerable<ExamViewModel> examViewModel = AutoMapper.Mapper.Map<IEnumerable<Exam>, IEnumerable<ExamViewModel>>(examsDb);
return View(examViewModel);
}
and in view I loop through it
#model IEnumerable<AraParsESOL.ViewModels.ExamViewModel>
<ul>
#foreach (var e in Model)
{
<li>
#Html.ActionLink(e.Title, "Type", "Exam")
</li>
}
</ul>
My problem is that:
As you can see in the Model There are 4 properties but in viewModel there are only 2 properties.
How can i get only those 2 properties in viewModel and not the entire Model?
What happens here is that in view after each loop it goes and get the required column from the database but i want only those 2 properties and not going back to database.
i can get the database like this
db.Exam.ToList();
but it will cause the entire database gets back.
i want to use best practices here?
i know i can get the data from database by anonymouse type and select command but then what is the use of automapper?
what is the best solution here?

Don't use AutoMapper. It's not appropriate for IQueryable<T>. Instead, use LINQ projections:
public ActionResult Exam()
{
var examsDb = db.Exams;
IEnumerable<ExamViewModel> examViewModel =
from e in db.Exams
select new ExamViewModel
{
NewsId = e.NewsId,
Title = e.Title
};
return View(examViewModel);
}
If you look at the generated SQL, you will see that only the NewsId and Title columns are retured. It looks like the AutoMapper folks were interested in addressing this shortcoming, but I haven't heard anything about it since this.

Related

Swagger-net breaks when using [FromUri] with a complex EF model

I'm using Swagger-Net in my .NET 4.5.1 WebAPI project and one of my API calls is causing the Swagger UI to spin forever on load before coming back with the error below.
Specifically, I found that using [FromUri] in combination with a complex EF entity that has references to other entities ends up causing this.
[HttpPost]
public APIResponse CreateSchool([FromUri]School school)
{
// save school object to db
}
public partial class School : IAuditableEntity,IEntity
{
public School()
{
this.Affiliations = new HashSet<Affiliation>();
this.SchoolAccreditations = new HashSet<SchoolAccreditation>();
this.SchoolAdultRoles = new HashSet<SchoolAdultRole>();
this.SchoolCareOptions = new HashSet<SchoolCareOption>();
this.SchoolDailySessions = new HashSet<SchoolDailySession>();
this.SchoolEligibilityRequirements = new HashSet<SchoolEligibilityRequirement>();
// ...more hashsets
[DataMember]
public int SchoolID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public bool Active { get; set; }
//...more properties
}
}
Is there a way to still use FromUri and the EF model? Or do I need to change my API call signature?

Explicitly load related entities within entities

I have object graph like the following:
Public ClassA
{
public int Id { get; set; }
public virtual ICollection<ClassB> ClassB_List { get; set; }
}
Public ClassB
{
public int Id { get; set; }
public virtual ICollection<ClassC> ClassC_List { get; set; }
}
Public ClassC
{
public int Id { get; set; }
}
Now what I would like to do is since I have disabled lazy load at the DBContext level, for a given ClassA instance, I would like to load allrelated entities (ClassBList and ClassCList).
I'm able to load the nested collection for ClassB_List using:
context.Entry(classA).Collection("ClassB_List").Load();
However, I don't know how to then load each child item within ClassB_List for ClassC_List without resorting to something rubbish like this:
classA.ClassB_List.ToList().ForEach(c => context.Entry(c).Collection("ClassC_List").Load());
Another way I know I found is use eager loading at the context using Include() :
var c = context.ClassA_list
.Include("ClassB_List.ClassC_List")
.ToList();
Which is fine for list of ClassA instance if I already had the property included within by DBContext model but I don't often want to do this and just want to use explicitly load.
Any ideas?
You have used the two ways to eager load:
Include
Load
if you want some flexibility you can do something like this:
var c = context.ClassA_list;
if (IWantTheRelatedTable)
{
c = c.Include("ClassB_List.ClassC_List");
}
var result = c.ToList();
You build an IQueryable, then when it has all the includes you need you execute it.

A better way to work with circular foreign key references for new objects in EF 5

I work with EF 5.0, DB first in a web project.
For our service layer, we use Agatha with AutoMapper, so all data arrives in the service layer as POCO objects.
I have a data structure that look like this:
public class FirstClass
{
public int Id { get; set; }
public int? SelectedSecondClassId { get; set; }
public SecondClass SelectedSecondClass { get; set; }
public ICollection<SecondClass> MySecondClasses { get; set; }
//other properties go here
}
public class SecondClass
{
public int Id { get; set; }
public int ParentSecondClassId { get; set }
public SecondClass ParentSecondClass { get; set; }
//other properties go here
}
Now imagine I try to update a FirstClass object and do the following in 1 go:
Create 2 new Secondclass objects in the MySecondClasses collection (both with id 0)
Set one of these newly created objects as the SelectedSecondClass
Then EF refuses to play ball. I can't get it to work. If I look in the changetracker, I see that the SelectedSecondClass on the entity is empty again, but the SelectedSecondClassId is set to 0. And that's something he can't resolve, because there are 2 objects with Id 0, before they are properly created.
If I do this, I can get stuff fixed:
var newId = -1;
foreach (var newSecondClass in firstClass.MySecondClasses.Where(x => x.Id <= 0))
{
newSecondClass.Id = newId;
newId --;
}
if (firstClass.SelectedSecondClass != null)
{
firstClass.SelectedSecondClassId = firstClass.SelectedSecondClass.Id;
}
// Send the updates to EF
As you understand, I feel like this is a bit hacked together and it would be easy for another developer to forget something like this. I would like to have a better way of doing this. Preferably in a way that I can 'fix' situations like this just before a SaveChanges() in my DbContext wrapper.
Can anybody point me in the right direction?

EF Code First With Two DbContexts

This should be a simple one involving EF Code first but I can't wrap my head around the documentation and all the examples I am finding are from older versions. I am working with the latest (4.1).
Anyway I have some models like:
public class Foo
{
public int ID { get; set; }
public Bar Bar { get; set; }
}
public class Bar
{
public int ID { get; set; }
public string Value { get; set; }
}
I used some scaffolding with Asp.Net MVC to create my controllers/repositories and when I create a 'Foo' object, it also creates a 'Bar' object even though I set the 'Bar' property from something stored in the database.
public class FooViewModel
{
public int ID { get; set; }
public int BarID { get; set; }
}
public ActionResult Create(FooViewModel foo)
{
var entity = new Foo()
{
ID = foo.ID,
Bar = _barRepository.Find(foo.BarID)
};
_fooRepository.InsertOrUpdate(entity);
_fooRepository.Save();
// more stuff
}
How can I use fluent syntax for EF in order to stop it from creating a new 'Bar' row in the database?
Update
Here is the generated repository code:
public void InsertOrUpdate(Foo foo)
{
if (foo.ID == default(int)) {
// New entity
context.Foo.Add(foo);
} else {
// Existing entity
context.Foo(foo).State = EntityState.Modified;
}
}
public void Save()
{
context.SaveChanges();
}
your _fooRepository and _barRepository need to share same DB context instance. If the are using two instances the Bar will be in added state.
The problem must be somewhere in your repository layer - using the same model directly with EF 4.1 produces the expected result - a new row in the Foos table with a bar FK column pointing to the existing Bar.

MVC 2 Validation and Entity framework

I have searched like a fool but does not get much smarter for it..
In my project I use Entity Framework 4 and own PoCo classes and I want to use DataAnnotations for validation. No problem there, is how much any time on the Internet about how I do it. However, I feel that it´s best to have my validation in ViewModels instead and not let my views use my POCO classes to display data.
How should I do this smoothly? Since my repositories returns obejekt from my POCO classes I tried to use AutoMapper to get everything to work but when I try to update or change anything in the ModelState.IsValid is false all the time..
My English is really bad, try to show how I am doing today instead:
My POCO
public partial User {
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
And my ViewModel
public class UserViewModel {
public int Id { get; set; }
[Required(ErrorMessage = "Required")]
public string UserName { get; set; }
[Required(ErrorMessage = "Required")]
public string Password { get; set; }
}
Controller:
public ActionResult Edit(int id) {
User user = _userRepository.GetUser(id);
UserViewModel mappedUser = Mapper.Map<User, UserViewModel>(user);
AstronomiGuidenModelItem<UserViewModel> result = new AstronomiGuidenModelItem<UserViewModel> {
Item = mappedUser
};
return View(result);
}
[HttpPost]
public ActionResult Edit(UserViewModel viewModel) {
User user = _userRepository.GetUser(viewModel.Id);
Mapper.Map<UserViewModel, User>(viewModel, user);
if (ModelState.IsValid) {
_userRepository.EditUser(user);
return Redirect("/");
}
AstronomiGuidenModelItem<UserViewModel> result = new AstronomiGuidenModelItem<UserViewModel> {
Item = viewModel
};
return View(result);
}
I've noticed now that my validation is working fine but my values are null when I try send and update the database. I have one main ViewModel that looks like this:
public class AstronomiGuidenModelItem<T> : AstronomiGuidenModel {
public T Item { get; set; }
}
Why r my "UserViewModel viewModel" null then i try to edit?
If the validation is working, then UserViewModel viewModel shouldn't be null... or is it that the client side validation is working but server side isn't?
If that's the case it could be because of the HTML generated.
For instance, if in your view you have:
<%: Html.TextBoxFor(x => x.Item.UserName) %>
The html that gets rendered could possibly be:
<input name="Item.UserName" id="Item_UserName" />
When this gets to binding on the server, it'll need your action parameter to be named the same as the input's prefix (Item). E.g.
public ActionResult Edit(UserViewModel item) {
To get around this, do as above and change your action parameter to item OR you could encapsulate the form into a separate PartialView which takes the UserViewModel as it's model - that way the Html.TextBoxFor won't be rendered with a prefix.
HTHs,
Charles
Ps. If I'm totally off track, could you please post some code for the view.