I'm using Entity Framework 5.0 for my MVC4 project. There's a problem with it. When i give a db model to any view, controller send model with no relationship
example;
I have User class and with relation departments
when i use it in controller
using(context)
{
var user = context.Find(id);
string department = user.Department.Name;
}
its working when call in context. but when i do that
using(context)
{
var user = context.Find(id);
return View(user);
}
and call in view like
Model.Department.Name
i got error.
Here is my answer but its not good
using(context)
{
var user = context.Find(id);
string department = user.Department.Name;
return View(user);
}
when i try to user Model.Department.Name in view i got no error i must do that for every relation when i use class as model. there is have better solution for this problem ? i want use all relationship in View without call these in controller.
I hope you can understand me, sorry my english.
On your DbContext you could use the .Include method to eagerly load the relations you need:
context.Users.Include(u => u.Department).FirstOrDefault(u => u.Id == id);
or if you are using an older version of entity Framework the generic version of this method might not be available:
context.Users.Include("Department").FirstOrDefault(u => u.Id == id);
The reason for this is that you haven't "loaded" the Department in your original code. As your context is wrapped in a using statement it's being disposed of before the view is created and therefore your user object lacks the data you want.
In your second code example you have specifically called into the related Department object and therefore it now exists within the User object.
You need to eager load the Department in your original line using something like
context.User.Include(c => c.Department).Find(id);
Now your user object should have this available in the view.
What are u trying to accomplish? List a view for a user with one or many departments?
Related
So if I want to add an artist to my website, and I create a model that holds that and some additional details like:
namespace SuperMusic.Models
{
public artist NewArtist { get; set; }
public IEnumerable<RecordCompanies> RecordCompanies
{
get { //some code to populate possible record companies }
}
Now I can have a view to create a new artist and my model could populate a drop down of record companies that the artist can be associated with.
But in my controller, I have to define "New Artist". I believe there are two ways to do this:
newArtistModel.NewArtist = context.artist.Create();
newArtistModel.NewArtist = new artist();
Is one of these more correct than the other? Or is there actually a difference in code and one of these is incorrect?
Thanks again for answer my noob questions!
the first option newArtistModel.NewArtist = context.artist.Create(); is the correct method for creating new instances as the Context will create Entity Framework aware proxy objects.
Proxy objects provide full support for navigation properties etc.
There's a more complete answer here
This artist is being used for the view, so it is only needed to render the form. There is no need for the EF context.
So when initializing the view:
newArtistModel.NewArtist = new artist();
Then, when you post the form and want to save the artist, you will need the context and can use: context.artist.Create();
I am learning MVC4 in Visual Studio and I have many questions about it. My first statement about MVC is that MVC's Model doesnt do what I expected. I expect Model to select and return the data rows according to the needs.
But I read many tutorial and they suggest me to let Model return ALL the data from the table and then eliminate the ones I dont need in the controller, then send it to the View.
here is the code from tutorials
MODEL
public class ApartmentContext : DbContext
{
public ApartmentContext() : base("name=ApartmentContext") { }
public DbSet<Apartment> Apartments { get; set; }
}
CONTROLLER
public ActionResult Index()
{
ApartmentContext db = new ApartmentContext();
var apartments = db.Apartments.Where(a => a.no_of_rooms == 5);
return View(apartments);
}
Is this the correct way to apply "where clause" to a select statement? I dont want to select all the data and then eliminate the unwanted rows. This seems weird to me but everybody suggest this, at least the tutorials I read suggest this.
Well which ever tutorial you read that from is wrong (in my opinion). You shouldn't be returning actual entities to your view, you should be returning view models. Here's how I would re-write your example:
public class ApartmentViewModel
{
public int RoomCount { get; set; }
...
}
public ActionResult Index()
{
using (var db = new ApartmentContext())
{
var apartments = from a in db.Apartments
where a.no_of_rooms == 5
select new ApartmentViewModel()
{
RoomCount = a.no_of_rooms
...
};
return View(apartments.ToList());
}
}
Is this the correct way to apply "where clause" to a select statement?
Yes, this way is fine. However, you need to understand what's actually happening when you call Where (and various other LINQ commands) on IQueryable<T>. I assume you are using EF and as such the Where query would not execute immediately (as EF uses delayed execution). So basically you are passing your view a query which has yet to be run and only at the point of where the view attempts to render the data is when the query will run - by which time your ApartmentContext will have been disposed and as a result throw an exception.
db.Apartments.Where(...).ToList();
This causes the query to execute immediately and means your query no longer relys on the context. However, it's still not the correct thing to do in MVC, the example I have provided is considered the recommended approach.
In our project, we will add a Data Access Layer instead of accessing Domain in controller. And return view model instead of Domain.
But your code, you only select the data you need not all the data.
If you open SQL Profiler you'll see that's a select statement with a where condition.
So if it's not a big project I think it's OK.
I can't see these tutorials but are you sure it's loading all the data? It looks like your using entity framework and entity framework uses Lazy laoding. And Lazy loading states:
With lazy loading enabled, related objects are loaded when they are
accessed through a navigation property.
So it might appear that your loading all the data but the data itself is only retrieved from SQL when you access the object itself.
My ASP.NET MVC 4 application uses Entity Framework v5, the Ninject and Ninject.MVC3 nuget packages, and data is being stored in SQL Server Express. Models were generated using the "EF 5.x DbContext Generator for C#" template. Lazy Loading Enabled is set to True in my edmx.
I'm using the repository pattern, with my repository and context living in a separate project in my solution that is referenced by the ASP.NET MVC 4 project.
So, the problem -- after saving a new object ("Trade") that's a property of a view model, I query the repository for that object. At that point, the navigation properties I would expect to be populated are null. See the comment in the Create() method below.
If I retrieve an existing Trade from the db (one that I didn't just save), all the navigation properties seem to be populated.
I found a report of a similar/identical problem on this page. The author of the article states, "I think this is a glitch in DbContext. Namely, Lazy loading for the foreign key navigation property doesn’t work for the newly added item, but the lazy loading for the navigation property in the many end works fine, such as Teacher.Classes. This glitch occurs only for the newly added item. If you don’t load Class.Teacher explicitly above for the newly added item, it will be null if it hasn’t been loaded somewhere in Entity Framework. However, if it is loaded already somewhere, then C.Teacher can be automatically resolved by Entity Framework. Whereas, for ObjectContext, lazy loading is fine for all types of navigation properties."
My controller's Create method looks like this:
[HttpPost]
public ActionResult Create(TradeViewModel tradeViewModel)
{
if (ModelState.IsValid)
{
_employeesRepository.SaveTrade(tradeViewModel.Trade);
var trade =
_employeesRepository.Trades.First(
x =>
x.RequesterId == tradeViewModel.Trade.RequesterId &&
x.RequesterWorkDate == tradeViewModel.Trade.RequesterWorkDate);
// Null reference encountered below, as trade.TradeType and trade.Employee are both null
String userMessage = "New " + trade.TradeType.TradeTypeDescription + " requested with '" + ControllerHelpers.GetDisplayName(trade.Employee) + "'";
TempData["UserMessage"] = userMessage;
return RedirectToAction("Index");
}
return View();
}
The SaveTrade() method in the employee repository looks like:
public void SaveTrade(Trade trade)
{
var data = (from t in _context.Trades
where t.RequesterId == trade.RequesterId
&& t.RequesterWorkDate == trade.RequesterWorkDate
select t);
if (!data.Any())
{
_context.Trades.Add(trade);
}
_context.SaveChanges();
}
And finally, Trades in _employeesRepository looks like:
public IQueryable<Trade> Trades
{
get { return _context.Trades; }
}
EF's deffered loading could be causing this. Try eagerly loading the employee like below
var trade =
_employeesRepository.Trades.Include("TradeType").Include("Employee").First(
x =>
x.RequesterId == tradeViewModel.Trade.RequesterId &&
x.RequesterWorkDate == tradeViewModel.Trade.RequesterWorkDate);
You can get a clearer picture if you try looking at the query that's being generated by EF. I'd use EfProfiler http://www.hibernatingrhinos.com/products/EFProf for this type of analysis. You can of course use your favorite tool.
Hope this helps.
Update
Here'a link to Julie Lerman's article that may help in understanding the deferred loading concepts http://msdn.microsoft.com/en-us/magazine/hh205756.aspx
Added tradetype in the include
You are probably creating the Trade by using New(). You should use your DBContext's Trades.Create() method instead.
I am new to MVC, so please excuse me if my question sounds silly or too simple. I am using Entity Data Model for database access. So in my Models folder, I have added an EDMX file and I can access the model classes from my controllers and strongly typed views. The problem arises when I access more than one table in my controller e.g.
If I have following tables in my DB :
Departments(DepartmentID, DepartmentName, DepartmentPhone)
Insurances(InsuranceID, InsuranceName, InsuranceAddress)
Employees(EmployeeID, EmpFName, EmpLName, DepartmentID, InsuranceID)
And I want to display a list of Employees with their department and insurance information.
In my Controller's Action Method I access the DB using EDM and get the information in an anonymous type:
using (var context = new MyEntities())
{
var model = (from d in context.Departments
join e in context.Employees on d.DepartmentID equals e.DepartmentID
join I in context.Insurances on I.InsuranceID equals e.InsuranceID
select new
{
DepartmentID = d.DepartmentID,
EmployeeID= e.EmployeeID,
EmpFName= e.EmpFName,
EmpLName= e.EmpLName,
DepartmentName= d.DepartmentName,
InsuranceName= I.InsuranceName
}).ToList();
return View(model);
}
I don't have a class of this anonymous type in my Model folder so I can't create a strongly typed view. So what is the best way to pass this list to the View?. Using viewbag will be an overkill if the collection is too large. Creating a new Model for this anonymous class doesn't sound right as it needs to be updated all the time if I change my selection in Controllers Action Method.
All suggestions are welcomed. I tried looking through other questions on SO but couldn't find anything relevant.
Thanks.
I don't have a class of this anonymous type in my Model folder so I
can't create a strongly typed view
Right click on your project, Add New Class ... and now you have a type in your Model folder. This is the way to go in ASP.NET MVC => view models.
And then obviously you pass this type to your view:
select new MyViewModel
{
DepartmentID = d.DepartmentID,
EmployeeID = e.EmployeeID,
EmpFName = e.EmpFName,
EmpLName = e.EmpLName,
DepartmentName = d.DepartmentName,
InsuranceName = I.InsuranceName
}).ToList();
And of course now your view becomes strongly typed to this view model:
#model IEnumerable<MyViewModel>
...
I'm afraid that predefined strongly-typed ViewModels are the way to go. It is a pain to have to update seemingly duplicate code in multiple places but in my experience it's only a problem for smaller projects. As the project grows you begin to see differences between database model objects (entities) and the viewmodels passed to your views, such as Validation and processing attributes and view-specific data, and when you get to that point you begin to prefer having separate Entity and ViewModel definitions.
However, back on-topic: an alternative solution to your problem is to use reflection to convert an anonymous type into a Dictionary<String,Object> object. Note that ASP.NET MVC does this for converting new { foo = "bar" }-syntax expressions into dictionaries for Route Values and HTML attributes already. Performance is acceptable, but don't try to do it for 10,000 objects for a single HTTP request otherwise you might get bogged down.
Here's what the code for that would look like:
Object anonymousType = new { whatever = "foo" };
Dictionary<String,Object> dict = new Dictionary<String,Object>();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(anonymousType )) {
Object value = descriptor.GetValue(anonymousType );
dict.Add( descriptor.Name, value );
}
Of course this means that your Views won't benefit from compile-time type-checking and you'll have to maintain a documented list of dictionary keys (assuming you aren't iterating over keys in your view).
I'll note that I am surprised Microsoft didn't make anonymous types automatically implement IDictionary because it seems natural.
dynamic type is your friend.
You can declare your view as loosely typed, having a dynamic as your model
#model dynamic
You will access model properties as you do in strongly typed view
<h1>Model.DepartmentId</h1> - <h2>Model.DepartmentName</h2>
<span>Model.EmployeeId</span>
The problem thought, that dynamics contains internal properties, if you are using MVC2 you need a little trick to make it work. But seems for MVC3 and higher, it's not longer required.
I have a simple form which inserts a new Category with the given parentID (ServiceID).
and my parent child relationship is this;
Service > Category
my url for creating a Category based on the ServiceId is this
/Admin/Categories/Create/3 => "3 is the serviceID"
and my Action method is this
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(int? id, Category category)
{
if (ModelState.IsValid)
{
try
{
category.Service = dbService.GetAll().WithServiceId(id.Value).SingleOrDefault();
dbCategory.Add(category);
dbCategory.Save();
return RedirectToRoute("List_Categories", new { ServiceId = id.Value });
}
catch
{
ModelState.AddRuleViolation(category.GetRuleViolations());
}
}
return
View ....
I am using LinqToSql for db actions. Anyway the strange part begins here.
When i save the data it inserts a data to Service table instead of insterting data just to Category Table and the data which is inserted to Category Table has the new inserted ServiceID.
Is it a problem with the ASP.NET MVC ModelBinder or am i doing a mistake that i dont see ?
I have used LinqToSql in several projects and have never had an issue like this
It could be an error in your LINQ To SQL set up. Is the service id an autogenerated field in the DB -- is it marked as such in the LINQ to SQL classes? Does your service disconnect it from the data context, then not reattach it before submitting? If so, have you tried adding the category to the service and then saving the updated service?
var service = ...
service.Categories.Add(category);
service.Save();
Where does your Category object come from? As I see you are relying on ASP.NET MVC Model binding for providing it but for that you need a form somewhere to make a POST. It would help to see the form too.
Also personally I rather use FormCollection (rather than business model classes) in my action signatures and then pull the posted data out from the FormCollection by myself. Coz sooner or later you end up having some complex objects with various one-to-many, many-to-many relationships that Model Binding just won't pick up and you have to construct it by yourself.