ASP.NET MVC (Code first) : Managing complex views - asp.net-mvc

I'm new in Asp.net MVC pattern. I used to develop website using asp.net web forms. I did research for hours about MVC and got a little understanding. But there're still some problems that keep confusing me.
(I decided to use Code First)
I have to display some pretty complex data, for my old project, i was using Stored Procedure, now i think i'm gonna change to LINQ, the questions are :
Does it affect the performance ? I was having good performance with SP.
How do i "define" the objects created by the query (in this case is the result set), should i define it in model classes ?
To be more specific, this is how i get things done in my old project, i have a class called ReportData (please note this is a mini-version, the actual class contains more properties) :
public class ReportData
{
public string CityID { set; get; }
public DateTime ResultDate { set; get; }
/// ...
// free fields
public int INT1 { set; get; }
public int INT2 { set; get; }
public int INT3 { set; get; }
public int INT4 { set; get; }
public string STR1{ set; get; }
public string STR2 { set; get; }
public string STR3 { set; get; }
public string STR4 { set; get; }
}
And everytime a Stored Procedure is executed, i put the result into this class, and build the HTML markup from this class :
foreach (ReportData r in listReportData)
{
// build html markup here
}
This way i can save a whole lot of works, i don't have to write code twice for any "same same" results. And it's running ok, but i have to change due to some circumstances.
Now when stepping into MVC world, i found it very confused and honestly i'm now lost with the controlers, models, and views stuffs.
I also read about some related topic which pops up when i was typing this question, but they seem doesn't help me much in my case, oh i'm too nerd to understand the answers!

Related

How to design EF core code-first database when different tables share the same fields

I'm working on a ASP .NET Core 5 MVC application with MS-SQL database and EF Core is my ORM (with the code-first approach).
Currently I'm redesigning the database, I have multiple tables that share a lot of the same properties, and I want to be able to add/remove properties from different tables, but only in one place in the code.
Because .NET doesn't have multiple class inheritance, I came up with the idea to inherit the classes in "levels".
Basically, in the example below, the purchases table and the products table should have exactly the same prices, dates and content properies, but also some additional specific fields:
class Purchase : PriceDatesAndContent
{
// specific purchase properties
}
class Product : PriceDatesAndContent
{
// specific product properties
}
class PricesDatesAndContent : PriceAndDates
{
public string Name { get; set ; }
public string Description { get; set; }
}
class PricesAndDates : Prices
{
public DateTime someDate1 { get; set; }
public DateTime someDate2 { get; set; }
// ...
}
class Prices
{
public double Price1 { get; set; }
public double Price2 { get; set; }
}
However, I'm not really sure that this is really a brilliant idea as it seems to me, I would love to hear your opinion, or maybe you even have another workaround for this scenario?
Thank you very much!
However, I'm not really sure that this is really a brilliant idea as it seems to me
Having a deep inheritance hierarchy is fine so long as your base classes aren't mapped as Entities. But it is unusual to model your classes this way just to save yourself a bit of typing.
It would probably be better to use interfaces to model the common property patterns, so you don't have to arrange them in a single hierarchy. eg
public interface IHasName
{
public string Name { get; set; }
public string Description { get; set; }
}
public interface IHasPrices
{
public double Price1 { get; set; }
public double Price2 { get; set; }
}

Is it good practice to use object-object mappers, and, if so, where to use it?

I've googled some around the internet and found some articles about the subject, but none of them satisfied me. I want to know is it good to use object-object mapper to map objects to each other? I know it depends on situation to use, but how will I realize a good or best situation to use?
Taking a step back, it's best practice to separate data transfer objects (DTOs) and view models (VMs) from business objects (entities and alike). Mapping libraries, in that regard, are a means to an end and simply make that association easier.
As far as when, that's up to you. If you feel like you can convert between your business models and DTO/VMs in a way that's easy to maintain, go ahead. From my personal experience, that only goes so far (especially as the requirements change). Therefore, I'm fond of mapping libraries (specifically AutoMapper as I've come to know it's API and am comfortable plugging it in).
Having said that, any time I have to go between these two models I use AutoMapper. I simply configure it once and I'm off and running. Additional tweaks to the models (on either side) then become easier as I can change those bindings in one place (map definition file) and methods automatically "catch up".
Example:
My database contains a Record for a product:
class Product
{
public int Id { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public int QuantityOnHand { get; set; }
public int? ReorderQuantity { get; set; }
public string Sku { get; set; }
}
I may present this to the UI in a more distilled format:
public class ProductViewModel
{
public int Id { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public int Quantity { get; set; }
}
If this came from a repository of some kind, I'm simply calling:
var model = Mapper.Map<ProductViewModel>(productFromRepository)
Here I consistently get the view model I care about from the Product I've requested. If the business/service layer were to add/change/remove properties, I'd only go back to my Mapper.CreateMap<Product, ProductViewModel>() defintion, but the rest of my presentation logic would remain in-tact.
In addition to #Brad Christie's answer, automapping types which have minor differences into a single overarching type is generally easier if you are meaning to display them on your view alongside other products that are generated different ways.
If you'll allow me to crib off one my own previous answers, here's an example:
class SingleProduct {
string Name {get;set;}
decimal Price {get;set;}
decimal GetActualPrice() { return Price; }
}
class ComboSaleProduct {
string Name {get;set;}
List<SingleProduct> ComboProducts {get;set;}
decimal GetActualPrice() { return ComboProducts.Sum(p => p.GetActualPrice()); }
}
class ProductViewModel {
string Name {get;set;}
decimal ActualPrice {get;set;}
}
Automapper wires everything together so that you can return either of these and it will automatically map the "GetActualPrice" to ActualPrice on your viewmodel.

$orderby on One To Many Navigation Property in OData

Looking for way to do $orderby on a one to many navigation property using OData v4 under WebApi2. As an example, a classic Contact and Address scenario where there is a one to many.
public class Contact
{
public int ContactId { get; set; }
public String FirstName { get; set; }
public virtual ICollection<ContactAddress> Addresses { get; set; }
}
public class ContactAddress
{
public int ContactAddressId { get; set; }
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }
public String AddressOne { get; set; }
public String StateCode { get; set; }
public bool IsPreferred { get; set; }
public String Type { get; set; }
public bool IsActive { get; set; }
}
Where we want to support composing queries that might include ordering by the preferred address StateCode, etc.
I realize that the following won't work as it doesn't terminate in a single value / object:
http://localhost:49380/odata/ODataContacts?$filter=LastName eq 'Smith'&$expand=Addresses&$orderby=Addresses/StateCode
But what I am trying to understand is what the options are to deal with this. It is such a fundamental scenario. In straight LINQ world it is pretty easy to build an expression that will do the appropriate sub filtering on Addresses to allow this. But would like to avoid special case as really trying to just support simple query composition through the OData URL / filter and orderby conventions.
What would be ideal would be something like:
http://localhost:49380/odata/ODataContacts?$filter=LastName eq 'Smith'&$expand=Addresses&$orderby=Addresses($filter=IsPreferred eq true)/StateCode
But this doesn't seem to be supported, at least in OData4 as it is in WebApi.
I have pondered a custom function, and per spec this should be supported in an $orderby expression. But have stumbled on how to implement this. The assumption would be something like:
http://localhost:49380/odata/ODataContacts?$filter=LastName eq 'Smith'&$expand=Addresses&$orderby=ContactService.PreferredAddress(ContactId=$it.ContactId)/StateCode
I have not been successful with this, and it strikes me this will all be "too late" to build the query expression for server side execution regardless, as it is really just a call to another endpoint.
I also stumbled upon some of the ModelBinding functions, many of which take lambda expressions, which seems promising. So for example:
builder.EntitySet<Contact>("ODataContacts")
.HasOptionalBinding<ContactAddress>(c => c.Addresses.FirstOrDefault(a => a.IsPreferred), "PreferredAddress");
Only I am not clear on what I then need to do on actual Entity or Controller to make this all work. I am getting a runtime exception as PreferredAddress doesn't really exist anywhere. But it would seem this is the approach that might work the best?
I can probably get things to work with a DTO/Queryable approach but this seems really unfortunate and a lot of extra work.
Is there a practical approach to this problem???

Scaffolding entity relationships with MVC5 EF6

Im learning MVC 5 with Entity Framework 6. How can i make the model support relationships between my classes. Like a one Employee can have several Tasks. Is it possible to make the scaffolding set it up automagically?
Ive read some similar tutorials for earlier versions but they dont seem to apply. So i ask for answers from someone who has experience of MVC5 with EF6.
Without any code to base this on, here's all you really have to do to set up a one-to-many relationship in EF6:
public class Employee
{
public int ID { get; set; }
public string name { get; set; }
public List<Task> Tasks { get; set; }
}
public class Task
{
public int ID { get; set; }
public string Title { get; set; }
public Employee AssignedEmployee { get; set; } //Not required, but it would be nice to easily access the owner of a task from code.
[ForeignKey("AssignedEmployee ")]
public int EmployeeID { get; set; } //Also not required, but comes in handy often. Just holds the ID of the assigned employee. I always include this, but it's just a preference.
}
Just remember to add these to classes as properties to your EF context. This is a simple example, since you're not very specific with what you want to achieve. :)

Retrieving related data using linq

I have an MVC app using EF code first. I add a user to the system and enter pension details, part of this is a dropdown linked to a model called PensionBenefitLevel. This is the model -
[Key]
public int PensionBenefitLevelID { get; set; }
public string DisplayText { get; set; }
public int EmployeePercentage { get; set; }
public int EmployerPercentage { get; set; }
public virtual ICollection<Pension> Pension { get; set; }
When registered I have the PensionBenefitLevelID that came from the dropdown, but in my controller I was to peform a calculation using the EmployerPercentage value that is related to that ID. Can anyone point me in the correct direction?
Do I need to create a variable in the controller and use a linq query to get that value back? I've not been able to find any examples of something similar so if you could point me to one that would be great too.
If I understand the question correctly, you want to get back the entity corresponding to PensionBenefitLevelID and perform a calculation on the EmployerPercentage field.
Since you haven't mentioned what pattern you are using with EF (repository, unit of work, etc.) I can only give you a general answer:
var entity = [Your DB Context].[Your Entity].GetById(pensionBenefitLevelID);
if(entity != null)
{
[Calculation]
}

Resources