I'm new to MVC and am used to using Forms. My question is suppose I have basic models setup for four tables with the following fields;
Branch
------
Branch_Nu
Branch_Address
Orders
-----
Order_Nu
Branch_Nu
Product_Nu
Customer_Nu
totcost
Products
---------
Product_Nu
Product
Price
Customer
----------
Customer_Nu
Name
Address
City
St
Zip
I'm interested in the following scenarios,
I want to see all orders for a branch;
Branch->orders
I want to see all orders for a customer from a particular branch;
Branch->orders->products
|-->customer
I want to see all orders for a customer regardless of branch they
purchased from;
customer->orders->branch
I want to see all branches that sold a particular product;
products->orders->Branch
I want to see which customers bought a particular product;
products->orders->customer
Question is can I use different controllers for the different scenarios using the same basic models that is submitted to different controller methods, or do I need different models for the different scenarios which is then submitted to different controller methods?
If I were using forms I would just have a different select statements and forms for each scenario, in MVC?
your entity framework models represent the relationships between your classes. In a code first approach, your models will dictate the design of your database. Take the following three classes for example:
public class Cat
{
[Key]
public int Id {get; set;}
public string Name {get; set;}
//Foreign key to animalgroup table
public int AnimalGroupId {get; set;}
//navigation property to AnimalGroup
//allows you to do myCat.AnimalGroup outside of this class to retrieve
//the associated animal group
public virtual AnimalGroup AnimalGroup {get; set;}
}
public class Dog
{
[Key]
public int Id {get; set;}
public string Name {get; set;}
public bool IsFluffy {get; set;}
//Foreign key to animalgroup table
public int AnimalGroupId {get; set;}
//navigation property to AnimalGroup
//allows you to do myDog.AnimalGroup outside of this class to retrieve
//the associated animal group
public virtual AnimalGroup AnimalGroup {get; set;}
}
public class AnimalGroup
{
[Key]
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<Cat> Cats {get; set;}
public virtual ICollection<Dog> Dogs {get; set;
}
this represents two one-to-many relationships. A AnimalGroup can contain multiple Cats and an AnimalGroup can contain many Dogs. You can write queries to do CRUD operations. A very simplistic example is the following:
//create and save an animal group
AnimalGroup group = new AnimalGroup();
group.Name = "my animal group";
_dbContext.AnimalGroups.Add(group);
_dbContext.SaveChanges();
//create and save a cat associated with the animal group
Cat myCat = new Cat();
cat.Name = "kitty";
cat.AnimalGroupId = group.Id;
_dbContext.Cats.Add(myCat);
_dbContext.SaveChanges();
Question is can I use different controllers for the different scenarios using the same basic models
Yes
do I need different models for the different scenarios which is then submitted to different controller methods
You don't need them, but generally speaking using a model for a different logical function tends (not always) to break the Single Responsibility Principle.
In your instance it appears you are viewing the same data by different views (not logic). An order is an order, for viewing purposes anywhere on your site, generally I use the same model. Placing an order (different logic function) I would most likely have a new model.
Considering you are viewing the same data this is a classic example of the best use of MVC Templates.
If I were using forms I would just have a different select statements and forms for each scenario, in MVC?
I would probably design it like:
I want to see all orders for a branch;
Branch->orders
public class BranchController() { public ActionResult Orders() {}}
I want to see all orders for a customer from a particular branch;
Branch->orders->products
|-->customer
public class BranchController()
{
public ActionResult Orders() {}
public ActionResult CustomerOrders() {}
public ActionResult ProductOrders() {}
}
// ETC
A model example:
public class OrderVM
{
//I would get rid of hungarian notation
// https://stackoverflow.com/questions/111933/why-shouldnt-i-use-hungarian-notation
public int OrderId { get; set; }
public int BranchId { get; set; }
public int ProductId { get; set; }
public int CustomerId { get; set; }
}
Then store how the html is rendered in /views/shared/templates/display/OrderVM.cshtml so it can be used throughout the application, allowing overrides per controller/area as well.
Related
I want to create a ViewModel, which is almost identical to the underlying Model, but with 2 added attributes. As an example, I have a Model named Person and the ViewModel would then look like:
public class PersonVM : Person
{
public string Subscription {get; set;}
public int? OtherAttribute {get; set;}
}
Is this the most optimal scenario or should I not inherit, but include it in the class like this?
public class PersonVM
{
public Person Person {get; set;}
public string Subscription {get; set;}
public int? OtherAttribute {get; set;}
}
The advantage of inheritance would be maintainability and ease of coding. When calling an attribute in the first scenario would be direct e.g. PersonVM.LastName, while in the second scenario the same call would be longer and potentially confusing: PersonVM.Person.LastName. What should be the considerations when choosing between these alternatives?
What is the proper usage of entities and DTOs when performing database actions? My mindset is that it seems best to use DTOs when reading from a database and entities when creating/updating to a database. As a small example let's consider teh following:
Book Class
public class Book/Entity
{
public int Id {get; set;}
public string Title {get; set;}
public int AuthorId {get; set;}
public Author Author {get; set;}
}
Author Class/Entity
public class Author
{
public int Id {get; set;}
public string Name {get; set;}
public int BookId {get; set;}
public Book Book {get; set;}
}
BookAuthorDto Class
public class BookAuthorDto
{
public string Title {get; set;}
public string Name {get; set;}
}
Now, let's say we have a WebApi Book controller.
public class BookController : ApiController
{
public IHttpActionResult GetBook(int id)
{
var BADto = context.Book.Where(book => book.ID == id)
.Select(book => new BookAuthorDto
{
Title = book.Title,
Name = book.Author.Name
});
return Ok<BookAuthorDto>(BADto);
}
public IHttpActionResult PostBookEntity(Book book)
{
// Code for saving book to DB
}
public IHttpActionResult PostBookDto(BookAuthorDto BADto)
{
// Code for creating entities from DTO
// Code for saving the created entities to Database
}
}
Which method is considered more "proper" the PostBookEntity method, or the PostBookDto Method?
Actually it is a good idea to separate queries from data modifications (insert, update, delete) - this is called Command Query Responsibility Segregation pattern (CQRS).
Here are some great posts from experts
An introduction to CQRS by M.Fowler
Some good reasoning on why Entities + Dto's are better than just using Entities for all cases
Entities pretty much are DTOs. Use the entity for all database access, and use view models in your actions.
I've tinkered with derived classes, interfaces and viewmodels, but I haven't been able to create quite what I need.
Say we're building a CMS with the following models:
ArticleItem
Title
Summary
Content
NewsItem
Headline
PublishDate
Summary
Content
EventItem
EventTitle
StartDate
EndDate
Content
I'm looking for a way to standardise the display of these into one format / view (e.g. so we can display them all in the same RSS feed). The standardized view might be called HTMLItem and have 3 fields:
Title
Summary
Content
The ArticleItem would translate directly to the HTMLItem, that's straightforward.
For the NewsItem I would like to join the PublishDate and the first 100 characters of the content to create Summary field of HTMLItem.
For the EventItem I would like to combine the StartDate and EndDate to create the Summary field of HTMLItem.
Ultimately I'm looking for the easiest, most efficient way to be able to pass the 3 models into a single view that has been designed to display HTMLItem. My best shot so far has been to create a 'convertor' class for each model, but I can't help feeling that there is a better way to do this.
Any experience, expertise and advice would be much appreciated!
Make a ViewModel with the standarized properties and a constructor for each specialized class:
public class HtmlItemViewModel {
//Properties
public string Title {get; set;}
public string Summary {get; set;}
public string Content {get; set;}
//Constructor inside HtmlItemViewModel for each one of the specialized classes:
public HtmlItemViewModel(ArticleItem item)
{
this.Title = item.Title;
this.Summary = item.Summary;
this.Content = item.Content;
}
public HtmlItemViewModel(NewsItem item)
{
this.Title = item.Headline;
this.Summary = String.Format("{0} - {1}", item.PublishDate, item.Summary.Substring(0,1000));
this.Content = item.Content;
}
public HtmlItemViewModel(EventItem item)
{
this.Title = item.EventTitle;
this.Summary = String.Format("{0} - {1}", item.StartDate, item.EndDate);
this.Content = item.Content;
}
}
Then, on the method you use for your RSS Feed simply pass each entity to the constructor on each individual query. Like this:
//Example controller
public class RssController : Controller {
public ActionResult GetRssFeed(){
//Assuming you have a service for each item type
var articleList = ArticleService.GetArticles().Select(s => new HtmlItemViewModel(s));
var newsItemList = NewsItemService.GetNewsItems().Select(s => new HtmlItemViewModel(s));
var eventItemList = EventItemService.GetEvents().Select(s => new HtmlItemViewModel(s));
articleList.AddRange(newsItemList);
articleList.AddRange(eventItemList);
return articleList;
}
}
You can use Viewmodel Pattern in your project
Models and ViewModels are different. Don't confuse the ViewModel with
the MVVM pattern.
The use of a view model can make the interaction between model and
view more simple. A model can sometimes be over complicated having
other model objects as members, which could have model objects as
member etc..
By using a view model you have a good way to simplify what the view
deals with. This will also filter down what can be seen in
intellisense, so if you have different people developing the models
than those working on the views, creating a simple view model can make
it much easier for those just dealing with the UI.
The simple and most common solution to this is to create a composite view model class. This can be a composed class (containing references to your domain models), or a flattened class, referencing properties from each class individually.
So you could do this:
public class HtmlItemViewModel
{
public ArticleItem ArticleItem {get; set;}
public NewsItem NewsItem {get; set;}
public EventItem EventItem {get; set;}
}
Or this:
public class HtmlItemViewModel
{
//Article Item Properties
public string ArticleTitle {get; set;}
public string ArticleContent {get; set;}
public string ArticleSummary {get; set;}
//News Item Properties
public string Headline {get; set;}
public DateTime PublishDate {get; set;}
public string NewsItemSummary {get; set;}
public string NewsItemContent {get; set;}
//Event Item Properties
public string EventTitle {get; set;}
public DateTime StartDate {get; set;}
public DateTime EndDate {get; set;}
public string EventContent {get; set;}
}
Then, whichever way you choose to construct the view model, you will map the view model properties to the domain model(s) in the controller. You can do this mapping manually
HtmlItemViewModel.ArticleTitle = ArticleItem.ArticleTitle;
//and so on...
Or you can use a third party tool like AutoMapper
I tend to favor the flattened view model in most scenarios as it allows me to only send the data I need, no more, no less. And it also allows me to put my data annotations for input validation on the view model instead of the domain model.
In my MVC Site a Teacher login and should view his classes and all books used in his classes.
The teacher should not be able to see someone else class or book.
Here's my model
public class Teacher
{
public int Id { get; set; }
public string Name {get; set;}
}
public class Books
{
public int Id {get; set;}
public string Title {get; set;}
public int CourseId {get; set;}
}
public class Course
{
public int Id {get; set;}
public int Name {get; set;}
public int TeacherId {get; set;}
}
I use a RepositoryPattern with UnitOfWork.
In order to get all classes tobe showned I should put in my Controller this kind of line :
var classes = classRepository.All.Where(x => x.TeacherId == currentTeacher.Id)
Things will get worst with the BookControler since I need to check all classes of the currentTeacher:
var classes = classRepository.All.Where(x => x.TeacherId == currentTeacher.Id)
var books = bookRepository.All.Where(x => classes.Contains(y => y.Id == x.CourseId)
It seems to me that this kind of approach may lead to some functional bug.
what I would like to do is that when a teacher login my repositories auto-filter in order to keep only datas concerning the currentTeacher, therefore in my controller I would have :
var classes = classRepository.All; // Already filtered on currentTeacher
or
var books = bookRepository.All; // Already filtered on currentTeacher
Is this possible? And how?
Create a new All(IPrincipal user) method in which you pass in the current authenticated user. This All method will lookup the Identity.Name value in your object context's Teacher collection to get the ID which is then returned.
i.e. .Where(x => x.TeacherId == currentTeacher.Id) is the return value from this new All method.
I've been trying to create model in EF 4.1 to represent a database schema with a single table and column holding foreign keys from two other tables, but have had little luck with both annotations and the fluent API. A sample model is shown here:
public class User
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class Account
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class ExtendedAttribute
{
public Guid Id {get; set;}
public Guid ItemId {get; set;} // both Account.Id and User.Id stored here
public string Value { get; set; }
}
Currently the configuration for these entities looks something like this for both User and Account modelBuilders:
this.HasOptional(u => u.ExtendedAttributes).WithRequired();
Any thoughts on how to do achieve? Many thanks.
It is even not possible with the database itself and EF will not put any abstraction for that. You must have separate column and navigation property for each entity.