Entity framework Navigation Properties - asp.net-mvc

I am currently trying to develop my first .NET MVC application and so learning the main concepts.
In my application I have a table that displays a list of animals from an animals table. In the table I am also trying to display the animal breed, but I am pulling the breed from the Breed table on the foreign key stored in the Animal table
I am currently trying to use a Navigation Property to display the Breed text and not the ID so I
altered my Animal model to look like this
public partial class Animal
{
public int AnimalId { get; set; }
public Nullable<int> UserId { get; set; }
public string TagNo { get; set; }
public Nullable<int> Species { get; set; }
public Nullable<bool> Sex { get; set; }
public Nullable<int> AnimalBreed { get; set; }
public Nullable<System.DateTime> DOB { get; set; }
public Nullable<int> OwnershipStatus { get; set; }
public Nullable<System.DateTime> DateAdded { get; set; }
public Nullable<bool> BornOnFarm { get; set; }
public virtual Breed Breed { get; set; }
}
And my breed model looks like
public partial class Breed
{
public int id { get; set; }
public Nullable<int> SpeciesID { get; set; }
public string Breed1 { get; set; }
}
In my view I am trying to display the Breeds field from my animal model as shown below, but the breed column is just empty
<td>
#Html.DisplayFor(modelItem => item.Breed.Breed1)
</td>
Also finally, here is the code that i am using to send the model to the view
List<Animal> Animal1 = (from animals in db.Animals
where animals.Species == 2 && animals.OwnershipStatus == 1
&& animals.UserId == WebSecurity.CurrentUserId
select animals).ToList();
return View(Animal1);

First, don't pluralize single items. It creates confusion in your code:
public virtual Breed Breed { get; set; }
-or-
public virtual ICollection<Breed> Breeds { get; set; }
The virtual attribute allows lazy-loading (a query to fetch the breed will be issued the first time you try to access it). You pretty much always want to include virtual with the property so Entity Framework does not unnecessarily issue joins if you don't actually end up using the property. However, in this case, you are, so you'll want to tell EF to eager-load it by including .Include("Breed") in your query. However, that's just for optimization; it's not your problem here.
Your problem here is that Razor doesn't know how to display Breed. It's not a normal type, obviously, because you created it. So, what you really need is to display the actual property on Breed that you want:
#Html.DisplayFor(m => m.Breed.Breed1)
There's an alternate method, but it's more complex and probably overkill for this scenario. If you really want to use Breed directly, then you need to define a display template for Breed. You do that by adding a new folder to Views\Shared named DisplayTemplates. Inside that folder, add a view named Breed.cshtml. The name of the view here corresponds to the class name, not the property name. Inside that view, you'd do something like:
#model Namespace.To.Breed
#Html.DisplayFor(m => m.Breed1)
Then, in your view you could just do:
#Html.DisplayFor(m => m.Breed)
And Razor will use the display template to render the appropriate thing. Like I said, it's overkill for this, but in more complex object rendering, it might come in handy.

If lazy loading is not enabled in your DbContext, then you have to explicitly load (or use eager loading) the navigation properties.
See http://msdn.microsoft.com/en-us/data/jj574232.aspx
You'll end-up with something like:
var res = (from animals in db.Animals.Include("Breeds")
where animals.Species == 2 & animals.OwnershipStatus == 1
& animals.UserId == WebSecurity.CurrentUserId
select animals).ToList();

Related

Add data to different tables using same view and controller in mvc4

I am new to asp.net mvc4 and creating a project in it. I am stuck on the way.
First let me describe about my project. I am creating a product table and each product has some attributes. I have created a ProductAttribute Model and a AttributeValue Model to add attributes and their values. Then I have created a ProductAttributeValue Model to assign the attributes and their values to the Product.
Now my problem is that I want to use the same view to add Attribute and their values. Below are my models:
[Table("ProductAttribute")]
public class ProductAttribute
{
[Key]
[MaxLength(20)]
public string AttributeId { get; set; }
[Required]
[Display(Name = "Attribute Name")]
[MaxLength(100)]
public string AttributeName { get; set; }
[Required]
[Display(Name = "Datatype")]
[MaxLength(50)]
public string AttributeDatatype { get; set; }
[Required]
[Display(Name = "Is Active")]
public bool IsActive { get; set; }
[Required]
[Display(Name = "Attribute Type")]
[MaxLength(30)]
public string AttributeType { get; set; }
}
[Table("AttributeValue")]
public class AttributeValue
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(20)]
public string AttributeId { get; set; }
[Required]
[MaxLength(100)]
public string AttributeName { get; set; }
[Required]
[MaxLength(200)]
public string AttributeVal { get; set; }
public virtual ProductAttribute ProductAttribute { get; set; }
}
How can I insert values to different tables using one view and controller? If there is another way to do the same then please help me about that.
Thanks
I think I understand what you are getting at. First you are going to want to build a View Model. Something like
public Class Tables
{
public List<ProductAttribute> Products { get; set; }
public List<AttributeValue> Values { get; set; }
}
Set those lists from your controller and pass them to the view. On the view you will define the model like
#model Tables
and then in the view build your table in your manner of preference. I have used Html.WebGrid in the past but have been using just foreach loops recently
<table>
foreach(var temp in Model.Products)
{
<tr>
<td>
temp.Name, etc
</td>
</tr>
}
</table>
as for adding and creating I have never been a fan of creating or adding directly in the table and generally what I am showing in the table isn't all of the information that I want from them so I use context menus or edit buttons on the rows and then a add button in a context menu or just outside of the table that will redirect to an edit/add page and then navigate back. Then you can refresh the table with a post back, jquery, refresh a partial view, whatever way fits your situation best. Hopefully this helps :)
Oh, here is a link to people discussing best how to edit a table
How to edit tabular data (ASP MVC)
Update:
Any information passed to the view through the model and used on the page with a for (html.textboxfor, textareafor, etc) will be passed back to the controller. If those fields are changed then the changed value will be passed back.
public ActionResult Index(){
(build your table class)
return View(Tables);
}
[HttpPost]
public ActionResult Index(Tables tbl){
(pass values return from the view to your query for saving to the database)
{

MVC MultiSelect modelbinding

i want to be able to display and update my User's Organisations preferably using the htmlhelper Html.TextBoxFor(
I have an entityframework 5 database first database with relationships defined as expected on the 3 tables
User
Organisation
UserOrganisation
which yield the classes below
public partial class User
{
public System.Guid UserId { get; set; }
public string Fullname { get; set; }
...
}
public partial class Organisation
{
public int OrganisationID { get; set; }
public string Title { get; set; }
...
}
public partial class UserOrganisation
{
public System.Guid UserId { get; set; }
public int OrganisationID { get; set; }
}
I pass in the user as the model and also populate a list of potential organisations in the viewbag i.e.
ViewBag.PossibleOrganisations = OrganisationFactories.GetOrganisations()
and the razor markup is.
#Html.ListBoxFor(model => model.UserOrganisations,
new MultiSelectList(ViewBag.PossibleOrganisations,"OrganisationID","Title"))
Now this displays the list of Organisations correctly and i can multiselect them. But it doesn't show the selected Organisations, and it also wont write this back to the database when posting back (incidentally all other fields did write back prior to this change).
Does anyone have any suggestions or examples of a multiselect list working in this fashion?
Cheers
Tim

CRUD Views For Many-Many Relationship, Checkboxes

I am having a hard time trying to figure out what I need to do to get this to work. I'm learning ASP.NET MVC CodeFirst with EF. If I make a model I can simply add a controller for that model and add scaffolding to create views that automatically take care of CRUD. But now I have two models, Project and Category. They have a many to many relationship and database is designed correctly with the associative table without having to make a separate model for it. The code for the models is this....
public class Project
{
public int ProjectId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Testimonial { get; set; }
public virtual ICollection<Image> Images { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public Project()
{
Categories = new HashSet<Category>();
}
}
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public ICollection<Project> Projects { get; set; }
public Category()
{
Projects = new HashSet<Project>();
}
}
So I add my controllers and do the scaffolding. I go in and create my categories just fine. But when it comes to my Projects/Create view, I would like to make it so that all the categories are displayed as checkboxes. Also, I would like to ensure that at least one category is selected before being able to submit the form to create a project. How would I do this?
For an example of using check boxes in a similar scenario, see Adding Course Assignments to the Instructor Edit Page in this tutorial:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application

Custom Conditional validation on strongly typed view in MVC

I have a Person model and a student model. The student model has 2 FKs of PersonIDs; one for student and the other for parent.
My view looks like this:
#Html.EditorFor(m => m.student.Person.FirstName)
#Html.EditorFor(m => m.student.Person.DOB)
#Html.EditorFor(m => m.student.Father.FirstName)
The models would look like this:
public partial class Person
{
public int PersonID { get; set; }
[Required]
[PlaceHolder("First Name")]
public string FirstName { get; set; }
[PlaceHolder("Birth Date")]
public Nullable<System.DateTime> DOB { get; set; }
}
public partial class Student
{
public int Student_PersonID { get; set; }
public int Parent_PersonID { get; set; }
}
I want the DOB to be required field for the student but not for the parent. If I add [Required] attribute to the DOB element, then it requires it for both. Is there a way I can set a require a field on the view? or is there a way in the model or using validation attribute to do this?
fyi... i am using EF database first approach
thanks
I would suggest having the view model match the fields that are displayed in the view. If later a field is to be removed from the view, then it will also be removed from the domain model.
In this case, if your view is to display the following fields:
StudentFirstName
StudentDOB
ParentFirstName
ParentDOB
Then I would suggest having the following view:
public class PersonViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Or if instead you have 2 seperate views displaying:
StudentFirstName
StudentDOB
AND displaying:
ParentFirstName
ParentDOB
Then I would suggest having 2 seperate view models:
public class StudentViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
}
public class ParentViewModel
{
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Using the view models in this way will allow you to use the [Required] data annotations for the fields that require them rather than trying to create a workaround. Note that the view models are not to be confused with the domain models and therefore this data would then need to be mapped to the domain model.
Hope this helps.
If your application is a simple application you may not need to create a seperate business logic layer and most books only present MVC with simple models which may be fine. However, if you search around you will find other examples where developers recommend having a view model seperate from a business model such as this
I would also recommend reading Wrox Professional Enterprise .Net 2009 where chapters 7 & 8 give great examples of the business layer with discussions of the Transaction Script pattern, Active Record pattern and Domain Model pattern.
One way is to make a PersonRequired class that inherits from Person. Add a metadata class to PersonRequired so you have PersonRequiredMetaData and in that specific that the inherited DOB field is required. You would need to manually copy the values between the Person and PersonRequired classes or use AutoMapper. I hope there is a better answer than this!
Another option is to use FluentValidation that would let you do the validation separate from the model (doesn't use data annotations). I wonder if some people are using data annotations for database requirements and fluent validation for programmatic requirements.

How do I display data from multiple tables in a single MVC view

I am having a hard time solving the following with an MVC view.
My goal is to display data from multiple tables in a single MVC view. The bulk of the data comes from a table called Retailers. I also have another table called RetailerCategories which stores the retailerid from the Retailers table and also a categoryid linking to a Category table.
Note that there are multiple records for each retailerid in the RetailerCategories table.
In the view I want to show a list of retailers and with each retailer I want to show the list of categories applicable to them.
What would be the best way to accomplish this? Some of the things I have tried are covered in Can you help with this MVC ViewModel issue?
This however does not appear to be the right approach.
You need a view model specifically tailored to the needs of this view. When defining your view models you shouldn't be thinking in terms of tables. SQL tables have absolutely no meaning in a view. Think in terms of what information you need to show and define your view models accordingly. Then you could use AutoMapper to convert between your real models and the view model you have defined.
So forget about all you said about tables and focus on the following sentence:
In the view I want to show a list of
retailers and with each retailer I
want to show the list of categories
applicable to them.
This sentence is actually very good as it explains exactly what you need. So once you know what you need go ahead and modelize it:
public class CategoryViewModel
{
public string Name { get; set; }
}
public class RetailerViewModel
{
public IEnumerable<CategoryViewModel> Categories { get; set; }
}
Now you strongly type your view to IEnumerable<RetailerViewModel>. From here it is easy-peasy to do what you want in the view:
showing a list of retailers with each retail having a list of associated categories.
this could be also helpful;
video from chris pels
It is simple just do what I say step by step.
add connection string into web.config file
select models from solution explorer and add 4 classes as following
1st class for first table "i have employ table which have 3 columns
public class Employ
{
[Key]
public int Emp_id { get; set; }
public string Emp_name { get; set; }
public string Emp_city { get; set; }
}
2nd class for my tempo table
public class tempo
{
[Key]
public int ID { get; set; }
public int Emp_Id { get; set; }
public string subject { get; set; }
public string hobby { get; set; }
}
Now I create a third class in model folder which contain value that i want from employ table and tempo table
public class Alladd
{
public int ID { get; set; }
public int Emp_Id { get; set; }
public string subject { get; set; }
public string hobby { get; set; }
public string Emp_name { get; set; }
public string Emp_city { get; set; }
}
and the final class is datacontext class
public class DataContext:DbContext
{
public DataContext() : base("DefaultConn")//connection string
{
}
public DbSet<Employ> Empdata { get; set; }
public DbSet<tempo> Tempdata { get; set; }
}
now go to the Home controller and add code as below
public ActionResult file()
{
// IList<tempo> tempi=new List<tempo>();
IEnumerable<Alladd> model = null;
// model = getVerifydetails(id);
// return View(objcpModel);
List<Alladd> verify = new List<Alladd>();
cn.Open();
if (cn.State == ConnectionState.Open)
{
string query = "select Employ.Emp_name,Employ.Emp_id,Employ.Emp_city,tempo.hobby,tempo.id,tempo.subject from Employ inner join tempo on Employ.Emp_id=tempo.Emp_id;";//joining two table
SqlCommand cmd=new SqlCommand(query,cn);
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
verify.Add(new Alladd { Emp_name = dr[0].ToString(), Emp_Id= Convert.ToInt32(dr[1].ToString()), Emp_city = dr[2].ToString(), hobby = dr[3].ToString(),ID = Convert.ToInt32(dr[1].ToString()),subject= dr[4].ToString()});//filling values into Alladd class
}
cn.Close();
}
return View(verify);
}
now the final step is so simple
go to solution explorer
select views folder and left click on it and select add view
now name it as "file" which we give it into controller
check on create strongly type view
select model class from dropdown-> Alladd
select scaffold templet ->List
hit Add button
Now you're done
Happy coding...

Resources