Displaying data from two different model in a view - asp.net-mvc

I am a newbie learning ASP.NET MVC from book.I am using NInject to Implement IoC. I have created a data model for Job and Location as below
Table Name - JobDetails
JobId<PK>
LocationId<FK>
JobName
Table Name - Location
LocationId<PK>
LocationName
I have created Entities for Location and JobDetails as Below
JobDetails
public class JobDetails
{
[Key]
public int JOBID { get; set; }
public int LocationID { get; set; }
public string JOBNAME { get; set; }
}
Location
public class Location
{
[Key]
public int LocationID{ get; set; }
public string LocationName { get; set; }
}
Also I have my Abstract and Context Class for Job Details and Location as below
public interface IJobDetails
{
IEnumerable<JobDetails> jobDetailsInterface { get; }
}
public interface ILocation
{
IEnumerable<Location> locationInterface { get; }
}
public class EFLocationRepository : ILocation
{
public EFDbContext context = new EFDbContext();
public IEnumerable<Location> locationInterface
{
get { return context.Location; }
}
}
public class EFJobRepository : IJobDetails
{
public EFDbContext context = new EFDbContext();
public IEnumerable<JobDetails> jobDetailsInterface
{
get { return context.JobDetails; }
}
}
My Model class for Job and Location are as below
public class JobListViewModel
{
public IEnumerable<JobDetails> jobDetails { get; set; }
}
public class LocationListViewModel
{
public IEnumerable<Location> Location { get; set; }
}
In my JobDetail Controller I want to display the location name instead of Location Id.
My JobDetail controller is as below
public class JobController : Controller
{
public IJobDetails repository;
public JobController(IJobDetails job)
{
repository = job;
}
public ViewResult List()
{
return View(repository.jobDetailsInterface);
}
}
How to display Location Name instead of Location id in my Job View?
N.B-I am learning MVC from Adam Freeman book and trying to create something new.Please let me know what I have done is correct or not.

Adding to sleeyuen's response. You may want to add a "navigation" property to JobDetails model, like below:
public class JobDetails
{
[Key]
public int JOBID { get; set; }
public int LocationID { get; set; }
public string JOBNAME { get; set; }
public virtual Location JobLocation { get; set; }
}
Then you should be able to access Location name from view by doing: repository.jobDetailsInterface.JobLocation.LocationName
In your scenario I believe entity framework will be able to infer relationships from the model structure, so you won't need entity configuration set up
Please note, this approach leads to N+1
Hope this helps :)

Related

MVC DbContext pull out all model

i am using Database first method. EDMX file generated default Dbset(TableName) for me.
myDbContext.Table1.ToList();
myDbContext.Table2.ToList();
Can we have a ModelView Class which pull both table out with single line?
Instead of
Table1=myDbContext.Table1.ToList();
Table2=myDbContext.Table2.ToList();
can we have like
ModelView=myDbContext.ModelView;
Updated
public partial class ProductTb
{
public string ProductID { get; set; }
public string ProductArticleNumber { get; set; }
public string ProductName { get; set; }
}
public partial class ProductTbTWO
{
public string ProductID { get; set; }
public string ProductArticleNumber { get; set; }
public string ProductName { get; set; }
}
public class ProductModelView
{
public ProductTb{get;set;}
public ProductTbTWO{get;set}
}
Create a Partial Class of your DbContext and add your custom Code.
public partial class MyDbContext
{
private MyDbContext(string contextName) : base(contextName) { }
public static MyDbContextCreate() {
return new MyDbContext(ContextName);
}
public ProductModelView ModelView {// Get ProductTb and ProductTbTWO}
}
and use it var myDbContext= MyDbContext.Create() and myDbContext.ModelView
But I don't recommend to do something like that, Add a Service class to with public method to get your code, Data Layer shouldn't deal with View Models
i prefer using static class:
public static class Utilities
{
public static ProductModelView getProductViewModel()
{
using (var db = new myDbContext()
{
var vm = new ProductModelView();
vm.ProductTb = db.ProductTb.ToList();
vm.ProductTbTWO = db.ProductTbTWO.ToList();
return vm;
}
}
}
you can call it like:
var vm = Utilities.getProductViewModel();

Not able to fetch data in one to one related data in MVC

I am not able to fetch the Centers Location where as I am able to save and update it it database. Its only fetching where I am facing problem
public class Club
{
public Club()
{
this.Memberships = new HashSet<Membership>();
this.People = new HashSet<Manager>();
this.Center = new Center();
}
public int ClubId { get; set; }
public string ClubName { get; set; }
public System.DateTime OpenDate { get; set; }
[ForeignKey("Center")]
public virtual Center Center { get; set; }
public virtual ICollection<Membership> Memberships { get; set; }
public virtual ICollection<Manager> People { get; set; }
}
My center model
public class Center
{
[Key,ForeignKey("Club")]
public int ClubId { get; set; }
public string Location { get; set; }
public virtual Club Club { get; set; }
}
and the index method is
public ActionResult Index()
{
return View(db.Clubs.ToList());
}
Your reference to Center is virtual, so it is lazy loaded. Try this instead:
return View(db.Clubs.Include(c => c.Center).ToList());
https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazy
I noticed you're sending your entity model to the view. You may want to look into the viewmodel pattern and automapper. http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/

How can i use two models in same controller(EntityFramwork) and use each in different action?

I have made one model so far and added controller using EF, and made some list of books
public class Books
{
public string ImageUr { get; set; }
public string BookTitle { get; set; }
public string ShortDescription { get; set; }
public decimal Price { get; set; }
public string Author { get; set; }
public int ID { get; set; }
}
public class BooksDBContext : DbContext
{
public DbSet<Books> Book { get; set; }
}
and im displaying that list in this action:
public ActionResult Books()
{
return View(db.Book.ToList());
}
and my question is how can i make another model or database that will be passed into this action (viewpage for news about new books for example):
public ActionResult News()
{
View(db.News.ToList());
}
and the model for news to be something like this:
public class News
{
public string Title{ get; set; }
public string Subtitle { get; set; }
public string Content{ get; set; }
public int ID { get; set; }
}
Well maybe you can try out a viewmodel. When I started learning ASP.NET MVC I did the tutorial Working with data and learned a lot about entity framework and ASP.NET MVC! I will give you a link. ASP.NET working with data
For your solution some code:
UPDATE You will need some virtual properties in your classes to define the relationships: we have a one to many relationship because book can have more news items and news can only have one book.
public class Book //change your class name to book
{
public string ImageUr { get; set; }
public string BookTitle { get; set; }
public string ShortDescription { get; set; }
public decimal Price { get; set; }
public string Author { get; set; }
public int ID { get; set; }
public int NewsId { get; set; }
public virtual ICollection<News> News { get; set; }
}
public class News
{
public string Title{ get; set; }
public string Subtitle { get; set; }
public string Content{ get; set; }
public int ID { get; set; }
public int BookId {get; set; }
public virtual Book Book { get; set; }
}
if your want to use a viewmodel then add a new folder named viewmodels and add a new class
public class BookNewsViewmodel //viewmodel of book and News :)
{
public IEnumerable<Book> Books { get; set; }
public IEnumerable<News> News { get; set; }
}
In the DbContext
namespace yourProject.DAL
{
public class yourProjectContext : DbContext //this is a DbContext!
{
public yourProjectContext () : base("yourProjectContext") //A constructor
{
}
public DbSet<Book> Books { get; set; } //make a DbSet of your classes
public DbSet<News> News { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Pluralize your tablenames from Books to Book and from Newss to News :)
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
In your controller:
With viewmodel
public ActionResult BookNewsIndex()
{
var viewModel = new BookNewsViewmodel();
viewModel.Books = db.Books
.Include(n => n.News)
return View(viewModel.ToList()); //return your data.ToList() to your view
}
Without a viewmodel
public ActionResult BookNewsIndex()
{
var data = db.Books.Include(n => n.News);
return View(data.ToList()); //return your data.ToList() to your view
}
In your View named BookNewsIndex you can do this. I am not sure about this but you can give it a try
#model yourproject.ViewModels.BookNewsViewmodel for your viewmodel
OR
#model IEnumerable<yourProject.Models.Book> without viewmodel
with viewmodel
#model.Books.ShortDescription
#model.News.Subtitle
without viewmodel
#Model.First().ShortDescription get something from your book!
#Model.First().News.First().Subtitle get something from news!
In part 7 of the tutorial he will use a viewmodel
I hope this will help you!
This has nothing to do with MVC, but with Entity Framework.
You'll have to add the DbSet for News:
public class BooksDBContext : DbContext
{
public DbSet<Books> Book { get; set; }
public DbSet<News> News { get; set; }
}

How to reuse projections in Entity Framework?

I have an ASP.NET MVC application which uses Entity Framework to get data.
I need to transform Entites to Models before passing them to View. Projections can be very complex, but to keep it simple:
public static IQueryable<UserModel> ToModel(this IQueryable<User> users)
{
return from user in users
select new UserModel
{
Name = user.Name,
Email = user.Email,
};
}
This can be used in a controller like this:
return View(Repository.Users.ToModel().ToList());
Very good. But what if I want to use this projection inside another one? Example:
public static IQueryable<BlogPostModel> ToModel(this IQueryable<BlogPost> blogs)
{
return from blogs in blogs
select new BlogPostModel
{
Title = blog.Title,
Authors = blog.Authors.AsQueryable().ToModel(), // (entities are POCOs)
// This does not work, because EF does not understand method ToModel().
};
}
(let's suppose blog can have more then one author and it is of type User).
Can I somehow separate the projections and reuse them inside another ones?
Here's something that actually works (in a simple test application) to only select the requested fields:
namespace Entities
{
public class BlogPost
{
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual DateTime Created { get; set; }
public virtual ICollection<User> Authors { get; set; }
}
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Email { get; set; }
public virtual byte[] Password { get; set; }
public virtual ICollection<BlogPost> BlogPosts { get; set; }
}
}
namespace Models
{
public class BlogPostModel
{
public string Title { get; set; }
public IEnumerable<UserModel> Authors { get; set; }
}
public class UserModel
{
public string Name { get; set; }
public string Email { get; set; }
}
public static class BlogPostModelExtensions
{
public static readonly Expression<Func<BlogPost, BlogPostModel>> ToModelConverterExpression =
p =>
new BlogPostModel
{
Title = p.Title,
Authors = p.Authors.AsQueryable().Select(UserModelExtensions.ToModelConverterExpression),
};
public static readonly Func<BlogPost, BlogPostModel> ToModelConverterFunction = ToModelConverterExpression.Compile();
public static IQueryable<BlogPostModel> ToModel(this IQueryable<BlogPost> blogPosts)
{
return blogPosts.Select(ToModelConverterExpression);
}
public static IEnumerable<BlogPostModel> ToModel(this IEnumerable<BlogPost> blogPosts)
{
return blogPosts.Select(ToModelConverterFunction);
}
}
public static class UserModelExtensions
{
public static readonly Expression<Func<User, UserModel>> ToModelConverterExpression =
u =>
new UserModel
{
Name = u.Name,
Email = u.Email,
};
public static readonly Func<User, UserModel> ToModelConverterFunction = ToModelConverterExpression.Compile();
public static IQueryable<UserModel> ToModel(this IQueryable<User> users)
{
return users.Select(ToModelConverterExpression);
}
public static IEnumerable<UserModel> ToModel(this IEnumerable<User> users)
{
return users.Select(ToModelConverterFunction);
}
}
}
To test it without actually creating a database:
var blogPostsQuery = (
from p in context.BlogPosts
where p.Title.StartsWith("a")
select p).ToModel();
Console.WriteLine(((ObjectQuery)blogPostQuery).ToTraceString());

Mapping with automapper

I have a domain model:
public class Project
{
[Key]
public int ProjectID { get; set; }
public string Title { get; set; }
public string Slug { get; set; }
public string Content { get; set; }
public string Category { get; set; }
public string Client { get; set; }
public int Year { get; set; }
}
I have a view model (which is a portion of the above model):
public class ListProjectsViewModel
{
public IEnumerable<ProjectStuff> SomeProjects { get; set; }
public class ProjectStuff
{
public int ProjectID { get; set; }
public string Title { get; set; }
public string Slug { get; set; }
public string Content { get; set; }
}
// Some other stuff will come here
}
I have an action controller:
public ActionResult List()
{
// Get a list of projects of type IEnumerable<Project>
var model = m_ProjectBusiness.GetProjects();
// Prepare a view model from the above domain entity
var viewModel = Mapper.Map..........
return View(viewModel);
}
How can I code the mapping '........' with automapper ?
Thanks.
There are two steps.
1) Define a mapping with AutoMapper (this is usually done in some sort of bootstrapper called by Global.asax, etc.)
// since all of your properties in Project match the names of the properties
// in ProjectStuff you don't have to do anything else here
Mapper.CreateMap<Project, ListProjectsViewModel.ProjectStuff>();
2) Map the object in your controller:
// Get a list of projects of type IEnumerable<Project>
var projects = m_ProjectBusiness.GetProjects();
// Prepare a view model from the above domain entity
var viewModel = new ListProjectsViewModel
{
SomeProjects = Mapper.Map<IEnumerable<Project>, IEnumerable<ListProjectsViewModel.ProjectStuff>>(projects)
};
return View(viewModel);
The thing to note here is that you are defining a mapping between Project and ProjectStuff. What you are trying to map is a list of Projects (IEnumerable) to a list of ProjectStuff (IEnumerable). AutoMapper can do this automatically by putting that in the generic arguments as I did above. Your View Model that your view is using is wrapping your list of ProjectStuff, so I just create a new ListProjectsViewModel and do the mapping inside of that.

Resources