The neat and simple way for multiple models in a view - asp.net-mvc

What can be simplest way for having rendered in a view information from multiple models. I use ViewModel in some scenarios (in particular when models are not related directly), but now I want to made a kind of dashboard for the current user. So apart from AspNetUsers model I have for example several models (e.g. Orders, OperationJournal, Jobs etc.) that in terms of entity have each a foreign key on UserID.
I made a ViewModel such:
namespace JobShop.Models
{
class QuickProfileVM
{
public IEnumerable<Jobs> Jobs { get; set; }
public IEnumerable<AspNetUsers> AspNetUsers { get; set; }
public IEnumerable<CreditJournal> CreditJournal { get; set; }
public IEnumerable<CandidateReview> CandidateReview { get; set; }
}
}
(since the base models that I need, are done by EF they have all about relations between entities) but it seems to me that is not enough. I am not able to view both the current user profile (so one record) and it's details (more than one record and more than one model).
I have try with Partial View, both with own controller or with actions in Dashboard View controller.
As an example an ActionResult that now I play with:
public ActionResult QuickProfile()
{
var QuickProfile = new QuickProfileVM();
var AspNetUsers = new AspNetUsers();
if (User.Identity.IsAuthenticated)
{
var CurrentUser = User.Identity.GetUserId();//UserManager.FindById(User.Identity.GetUserId());
var TheUser = db.AspNetUsers.Where(u => u.Id == CurrentUser)
.Select(u => new
{
ID = u.Id,
Email = u.Email,
PhoneNumber = u.PhoneNumber,
Companyname = u.Companyname,
Address = u.Address,
ZIP = u.ZIP,
City = u.City,
Country = u.Country,
Website = u.Website,
Facebook = u.Facebook,
Twitter = u.Twitter,
GooglePlus = u.GooglePlus,
Dribble = u.Dribble,
BirthDate = u.BirthDate,
Username = u.UserName,
Surrname = u.Surname,
Name = u.Name,
Role = u.Role,
ThumbURL = u.ThumbURL,
CreditBalance = u.CreditBalance
}).Single();
var TheJournal = db.CreditJournal.Where(tj => tj.UseBy == CurrentUser)
.Select(tj => new
{
IdJournal = tj.IdJournal,
Operation = tj.Operation,
CvID = tj.CvID,
JobID = tj.JobID,
CreditConsumed = tj.CreditConsumed,
UseDate = tj.UseDate,
UseBy = tj.UseBy
}).ToList();
//similar for Jobs and CandidateReview
//
var UserId = TheUser.ID;
var username = TheUser.Username;
var role = TheUser.Role;
var InitialCredit = TheUser.CreditBalance;
AspNetUsers.UserName = TheUser.Username;
AspNetUsers.Companyname = TheUser.Companyname;
AspNetUsers.Surname = TheUser.Surrname;
AspNetUsers.Name = TheUser.Name;
AspNetUsers.ThumbURL = TheUser.ThumbURL;
AspNetUsers.CreditBalance = InitialCredit;
//I put this to ilustrates what I have accesible for example
//about CreditJournal: only methods, not properties
QuickProfile.CreditJournal.AsEnumerable();
var id = CurrentUser;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
AspNetUsers aspNetUsers = db.AspNetUsers.Find(id);
if (aspNetUsers == null)
{
return HttpNotFound();
}
}
return View(AspNetUsers);
//Disbled since at this stage is not usefull
//return View(QuickProfile);
//return View();
}

I suggest you consider using Html.RenderAction in your view. For example, say your main dashboard is this:
#{
ViewBag.Title = "title";
}
<h2>Multiple Models</h2>
#{ Html.RenderAction("GetData", "Foo"); }
You can use Html.RenderAction to call FooController.GetData()
public class FooController : Controller
{
public ActionResult GetData()
{
var viewModel = new FooViewModel();
viewModel.TimeStamp = DateTime.UtcNow;
return View(viewModel);
}
}
So rather than having one viewmodel with lots of other viewmodels attached as properties, you can split up the rendering of the dashboard view.
Overall this should makes things easier for you - I've used this approach in the past and have found it reduces complexity.

Related

What's the return value of DBSet.Add(object o)

Consider the situation.
I have a userlogin table. the userlogin has the following fields.
userid(identity(1,1)), username(unique), password(string)
I have another table, userRole with following fields.
userid(fk referencing userlogin), role(string)
Now suppose I want to add an admin user to my empty application database.
What I am currently doing is:
// Check Userlogin if it contains adminuser1 as username, if not, add adminuser1 with password xyz.
UserLogin login = new UserLogin();
login.username = "adminuser1";
login.password = "xyz";
context.UserLogins.Add(login);
context.SaveChanges();
// query again from database to get the userid
Userlogin user = context.UserLogins.Single(l => (l.username == "adminuser1") && (l.password == "xyz"));
int userid = user.userid;
UserRole admin = new UserRole();
admin.userid = userid;
admin.role = "admin";
context.UserRoles.Add(admin);
context.SaveChanges();
I want to make it a less troublesome, if we can get the userid of userRecently Added, without making another request.
I mean I want to do this if it is possible.
UserLogin login = new UserLogin();
login.username = "adminuser1";
login.password = "xyz";
UserLogin user = context.UserLogins.Add(login);
UserRole admin = new UserRole();
admin.userid = user.userid;
admin.role = "admin";
context.UserRoles.Add(admin);
context.SaveChanges();
Update
I also wanted to know if there is some way to do
context.UserLogins.Single(l => l == login);
instead of
context.UserLogins.Single(l => (l.username == "adminuser1") && (l.password=="xyz"));
because I use the same method in large classes in many fields.
It can be different based on your needs but you can have something like:
public class UserRole
{
public int Id { get; set; }
public string role { get; set; }
}
public class UserLogin
{
public int Id { get; set; }
public string username { get; set; }
public string password { get; set; }
public UserRole Role { get; set; }
}
and then use them like:
var login = new UserLogin
{
username = "adminuser1",
password = "xyz"
};
var admin = context.UserRoles.Single(_=> _.role == "admin");
if (admin == null)
{
admin = new UserRole
{
role = "admin"
};
}
login.Role = admin;
context.UserLogins.Add(login);
context.SaveChanges();
Your models' relationship seems wrong but based on your information you can have this:
var login = context.UserLogins.Single(_ => _.username == "adminuser1");
if (login == null)
{
login = new UserLogin();
login.username = "adminuser1";
login.password = "xyz";
context.UserLogins.Add(login);
context.SaveChanges();
}
else
{
// this user already exists.
}
var admin = context.UserRoles.Single(_ => _.role == "admin");
if (admin == null)
{
admin.userid = login.userid;
admin.role = "admin";
context.UserRoles.Add(admin);
context.SaveChanges();
}
else
{
// the role already exists.
}
context.UserLogins.Single(l => l == login); would not work for you! you have to query DB based on your model key, not whole model data!
For the question
What's the return value of DBSet.Add(object o)
The answer is: it will return the same object o(i.e. without the userid). Simply because userid is an identity column and relies on the database, its value is only available after context.SaveChanges() is called. Since Add() method only registers that a change will take place after SaveChanges() is called.
For the answer to update,
Instead of using
context.UserLogins.Single(l => (l.username == "adminuser1") && (l.password=="xyz"));
For classes that have many fields, I can check if there are any unique columns. For example. I could use, simply
context.UserLogins.Single(l => l.username == "adminuser1");
Just because, username(unique) is specified in the question.
I would rather recommend people use a single Stored Procedure. The calling of context.SaveChanges() and the context.xyz.Single() require opening database connection multiple times. For optimising performance you can use Stored Procedures, as they require only one connection per task. For more information.
Understang Performance Considerations
As I am using database first approach, I found this link also helpful.
Use Stored Procedure in Entity Framework
Thanks :)

How to Convert Model to ViewModel in asp.net mvc

Here is my code:
public List<DiscountVM> GetAllDiscounts(long CompanyID)
{
return _context.Discounts.Where(x => x.IsActive == true && x.CompanyID == CompanyID).Select(s => new DiscountVM()
{
DiscountID = s.DiscountID,
LocationID = s.LocationID,
CompanyID = s.CompanyID,
DiscountName = s.DiscountName,
DiscountValue = s.DiscountValue,
DiscountType = s.DiscountType,
ServiceSale = s.ServiceSale,
ProductSale = s.ProductSale,
VoucherSale = s.VoucherSale,
IsActive = s.IsActive,
AddDate = s.AddDate,
AddedByID = s.AddedByID,
UpdateDate = s.UpdateDate,
UpdatedByID = s.UpdatedByID,
}).ToList();
}
I want to convert Model to View model because if i am not converting then i have to fill all the values.
The code is working fine if I fill all the values. I trying to find a way in which I can easily convert the model to view model then there would be no need to fill all the values.
well this can be done some different way but easiest way for you that change you view model a little bit by adding you db model as property of your view model like this
public class DiscountVM
{
public Discounts DiscountsList{ get; set; }
// Other property
}
and return like this
public List<DiscountVM> GetAllDiscounts(long CompanyID)
{
return _context.Discounts.Where(x => x.IsActive == true && x.CompanyID ==CompanyID).Select(s => new DiscountVM()
{
DiscountsList=s
}).ToList();
}
Have you looked into AutoMapper to help you with that?

Save userid on database when create new object

I have a Controller where on the Create action I need the user ID.
Here's the controller.
public ActionResult Create(MyCreateViewModel model)
{
if (ModelState.IsValid)
{
var myobject = new MyObject
{
Attrib1 = DateTime.Now.Date,
Attrib2 = model.Etichetta,
UserId = // I need the user ID...
};
// Save the object on database...
return RedirectToAction("Index");
}
return View(model);
}
I'm using the UserProfile table provided with the SimpleMembership of MVC 4.
Which is the best practice in MVC 4 to manage the userID across the application?
Do I have to include a User attribute inside every Entity class?
Should I use a Session[] variable or what?
You can use this line to get the userId from the UserProfiles table.
var userId = WebSecurity.GetUserId(HttpContext.Current.User.Identity.Name);
You can also use this function to get the users complete profile, including any custom columns you may be populating.
public static UserProfile GetUserProfile()
{
using (var db = new UsersContext())
{
var userId = WebSecurity.GetUserId
(HttpContext.Current.User.Identity.Name);
var user = db.UserProfiles
.FirstOrDefault(u => u.UserId == userId);
if (user == null)
{
//couldn't find the profile for some reason
return null;
}
return user;
}
}

Asp Net MVC with VM is this good practice? (Code Sample) [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'm wondering if what I have here is good practice. Using Entity Framework Code First with MVC and View Models.
Below i have code for List, Create, Edit and Delete. Model name Page and 2 ViewModels name ContentViewModel and ContentListViewModel.
private readonly IUserService _userService;
//private readonly MembershipProvider _members;
public ContentController()
{
// _members = Membership.Provider;
_userService = new AspNetMembershipProviderWrapper();
}
//
// GET: /Profile/Content/
public ActionResult Index()
{
using (var db = new BlogContext())
{
IEnumerable<Page> pages;
pages = db.ArticlePages.ToList();
List<ContentListViewModel> model = new List<ContentListViewModel>();
foreach (Page pg in pages)
{
MembershipUser user = _userService.Get(pg.authorId);
model.Add(new ContentListViewModel()
{
PageID = pg.pageID,
UserName = user.UserName,
UserID = (Guid)user.ProviderUserKey,
IsFrontPage = pg.frontpage,
isPublished = pg.published,
PageTitle = pg.titleHeading,
PageUrlName = pg.idName,
PublishedDate = pg.datentime
});
}
return View(model);
}
}
//
// GET: /Profile/Content/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Profile/Content/Create
[HttpPost]
public ActionResult Create(ContentViewModel page)
{
if (ModelState.IsValid)
{
using (var db = new BlogContext())
{
db.ArticlePages.Add(new Page()
{
authorId = (Guid)Membership.GetUser().ProviderUserKey,
datentime = DateTime.Now,
frontpage = page.FrontPage,
published = page.Published,
titleHeading = page.TitleHeading,
pageContent = page.Content,
idName = page.IdName
});
db.SaveChanges();
return RedirectToAction("Index").Success("Page added Successfully.");
}
}
return View(page);
}
//
// GET: /Profile/Content/Edit/5
public ActionResult Edit(int id = 0)
{
if (id == 0)
{
return RedirectToAction("Index").Error("Page Not found.");
}
Page pg = new Page();
using (var db = new BlogContext())
{
pg = (from m in db.ArticlePages where m.pageID == id select m).SingleOrDefault();
}
if (pg == null)
{
return RedirectToAction("Index").Error("Page Not found..");
}
return View(new ContentViewModel()
{
id = pg.pageID,
Content = pg.pageContent,
FrontPage = pg.frontpage,
Published = pg.published,
TitleHeading = pg.titleHeading,
IdName = pg.idName
});
}
// POST: /Profile/Content/Edit/5
[HttpPost]
public ActionResult Edit(ContentViewModel page)
{
if (ModelState.IsValid)
{
using (var db = new BlogContext())
{
var oPage = db.ArticlePages.Single(p => p.pageID == page.id);
oPage.frontpage = page.FrontPage;
oPage.idName = page.IdName;
oPage.pageContent = page.Content;
oPage.published = page.Published;
oPage.titleHeading = page.TitleHeading;
db.SaveChanges();
return RedirectToAction("Index").Success("Page updated");
}
}
return View(page);
}
//
// POST: /Profile/Content/Delete/5
[HttpPost]
public ActionResult Delete(int id)
{
using (var db = new BlogContext())
{
Page page = db.ArticlePages.Find(id);
db.ArticlePages.Remove(page);
db.SaveChanges();
return RedirectToAction("Index").Success("Page deleted");
}
}
I would like to know there are better ways of doing this?
While that method is certainly better than passing the entities directly to the view, I would suggest a number of improvements.
First, I would create a new business layer, and then create a facade class to retrieve your data. Then move all database access to this layer. Thus, you would end up with a call to the service layer rather than doing direct database access like you are doing above.
Second, you should look into using something like AutoMapper to map between your data entities and your view models.

two models in a view - not working for me

I have created an entity data model from my database. however in certain areas of the application i need to pass two models. thus i create a third model which has as properties the objects of each required model.
In the scenario, i want to use one model just to show some data to the user and the other is to be populated by the user using form elements. therefore, i create a constructor in my custom model to populate it. here's the code:
THE CUSTOM MODEL
public class ordersModel
{
public ordersModel(order or)
{
this.prods = new order_products();
this.new_order = new order();
this.new_order.customer_id = or.customer_id;
this.new_order.my_id = or.my_id;
this.new_order.my_order_id = or.my_order_id;
this.new_order.order_date = or.order_date;
this.new_order.order_status_id = or.order_status_id;
}
public order new_order { get; set; }
public order_products prods { get; set; }
}
IT IS USED IN THE CONTROLLER AS FOLLOWS:
public ActionResult Create()
{
order or = new order();
// Store logged-in user's company id in Session
//or.my_id = Session["my_id"].ToString();
//do something to allow user to select customer, maybe use ajax
or.customer_id = "123";
or.order_amount = 0;
or.my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
// display date picker to select date
or.order_date = DateTime.Now.Date;
// fetch statuses from database and show in select list box
or.order_status_id = 1;
return View(or);
}
//
// POST: /Orders/Create
[HttpPost]
public ActionResult Create(order or)
{
using (invoicrEntities db = new invoicrEntities())
{
var temp = db.last_order_number.SingleOrDefault(p => p.my_id == or.my_id);
if (temp != null)
{
or.my_order_id = temp.my_order_id + 1;
if (ModelState.IsValid)
{
ordersModel ord = new ordersModel(or);
db.orders.AddObject(or);
temp.my_order_id = temp.my_order_id + 1;
//TempData["my_order_id"] = or.my_order_id;
db.SaveChanges();
return RedirectToAction("AddProducts", ord);
//return RedirectToAction("AddProducts", new { id = or.my_order_id });
}
return View(or);
}
return RedirectToAction("someErrorPageDueToCreateOrder");
}
}
public ActionResult AddProducts()
{
using (invoicrEntities db = new invoicrEntities())
{
//string my_id = TempData["my_id"].ToString();
//string my_order_id = TempData["my_order_id"].ToString();
string my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
int my_order_id = 1;
//Int64 my_order_id = Convert.ToInt64(RouteData.Values["order_id"]);
// Display this list in the view
var prods = db.order_products.Where(p => p.my_id == my_id).Where(p => p.my_order_id == my_order_id).ToList();
var or = db.orders.Where(p => p.my_id == my_id).Where(p => p.my_order_id == my_order_id).ToList();
if (or.Count == 1)
{
//ViewData["name"] = "sameer";
ViewData["products_in_list"] = prods;
ViewData["order"] = or[0];
return View();
}
return RedirectToAction("someErrorPageDueToAddProducts");
}
}
[HttpPost]
public ActionResult AddProducts(order_products prod)
{
prod.my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
// find a way to get the my_order_id
prod.my_order_id = 1;
return View();
}
THIS ALL WORKS OUT WELL, UNTIL IN THE "ADDPRODUCTS" VIEW:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<invoicr.Models.ordersModel>" %>
AddProducts
<h2>AddProducts</h2>
<%: Model.new_order.my_id %>
the above statement gives an error
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
what am i doing wrong here?
You seem to be passing the wrong model when redisplaying your Create view.
Try passing the ord instance which is of type ordersModel and which is what your view is strongly typed to:
public ActionResult Create(order or)
{
using (invoicrEntities db = new invoicrEntities())
{
var temp = db.last_order_number.SingleOrDefault(p => p.my_id == or.my_id);
if (temp != null)
{
or.my_order_id = temp.my_order_id + 1;
ordersModel ord = new ordersModel(or);
if (ModelState.IsValid)
{
db.orders.AddObject(or);
temp.my_order_id = temp.my_order_id + 1;
db.SaveChanges();
return RedirectToAction("AddProducts", ord);
}
return View(ord);
}
return RedirectToAction("someErrorPageDueToCreateOrder");
}
}
UPDATE:
Now that you have shown your AddProducts action you are not passing any model to the view although your view expects an ordersModel instance. So don't just return View();. You need to pass an instance of ordersModel:
if (or.Count == 1)
{
ViewData["products_in_list"] = prods;
ViewData["order"] = or[0];
ordersModel ord = new ordersModel(or[0]);
return View(ord);
}

Resources