Entity Framework Code First Customer and Address Registration - c#

one for customer, and one for address.
Required Functionality When a customer registers, they enter their personal details such as name, tel as well as their address details in the same view.
Current Functionality
At present, EF scaffolding provides a dropdown list of addresses to choose from.
Current Code
public class Customer
{
public int CustomerId { get; set; }
public string FirstName { get; set; }
[Required]
public string Surname { get; set; }
[Required]
...
Customer Fields
...
public int AddressId { get; set; }
public virtual Address Address { get; set; }
}
public class Address
{
[Key]
public int AddressId { get; set; }
...
Address Fields
...
// Navigation Properties
public virtual List<Customer> Customer { get; set; }
}
When seeding the database, I can do so as follows:
new List<Customer>
{
new Customer
{
** Customer Fields ** ,
Address = new Address { ** Address Fields ** }
}
}.ForEach(c => context.Customers.Add(c));
base.Seed(context);
My thoughts
My initial thoughts are that I should create a 3rd Data model called CustomerWithAddress which is essentially a composite of customer and address models. This would allow me to scaffold a strongly typed view.
Alternatively, is it possible for a controller to pass 2 models to 1 view?
I don't know if this is the best way of tackling this problem, or in fact if it is possible. Any thoughts?

If your customer model has an address property, then you will be able to access it from your view. e.g.
#Html.DisplayTextFor(x => model.Address.Addressline1)
Your viewmodel Idea is a good one, but it's not necessary for this particular case.
EDIT: As my friend below pointed out, you may need to manually load the Address property if you are employing lazy loading.

Related

OData Expand override Entity Framework includes

Consider the following domain model:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int AddressId { get; set; }
public Address Address { get; set; }
public ICollection<Message> Messages { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
.....
}
public class Message
{
public int Id { get; set; }
public Message Message { get; set; }
}
We use EF6 code first to create the database for this model. The address data is saved to its own table.
On top of EF6 we use ASP.NET Web API 2.0 and OData.
The ODataConventionModelBuilder creates an EntitySet for Employee and a ComplexType for Address.
In order to return an Employee we created the following action:
[EnableQuery]
public SingleResult<Employee> Get([FromODataUri] int key)
In order to always return the Address we use an EF Include on the Address property. So when we use the following url:
/api/Employees(1)
The Employee with id 1 will be returned with its Address property filled.
However, when we use $expand to expand the Messages for the use we loose the Address data:
/api/Employee(1)?$expand=Messages
Returns an Employee object with Messages expanded, but without the Address data. The EnableQuery attribute applies the expand to our query-able but overwrites the EF Includes that we specified in the API.
We cannot expand the Address too from the client because Complex types cannot be expanded in OData.
When we change the Address Odata type to an Entity we need multiple calls to create or update an Employee. One call to an Address controler which handles create/update for addresses and one call to the Employee controller to handle create/update for employees.
So my question: Is it possible to preserve the Address include without specifying it from the client?
We use element type like Employee when select all properties, so we lose your include Address when composing the Linq expression, but if you select Address, it will come in result because it's not select all, so a work around maybe request like: $expand=Messages&$select=Address,Id,Name
Relative code: https://github.com/OData/WebApi/blob/master/OData/src/System.Web.OData/OData/Query/Expressions/SelectExpandBinder.cs#L272-L292

ViewModel Structure Decision

As my domain classes I have Person and FavoritePerson classes as follows.
public class CompanyPerson : ICompanyPerson
{
[Key]
public Guid PersonId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
public class CompanyFavoritePerson : IFavoritePerson
{
[Key]
public Guid FavoritePersonId { get; set; }
[Column(TypeName = "datetime2")]
public DateTime CreateDate { get; set; }
public Guid? CompanyPerson_PersonId { get; set; }
[StringLength(128)]
public string CompanyUser_UserId { get; set; }
public virtual CompanyPerson CompanyPerson { get; set; }
public virtual CompanyUser CompanyUser { get; set; }
}
In my web application I will need to show List of Favorite Person. So my view model is like this;
public class FavoritePersonViewModel
{
public Guid FavoritePersonId { get; set; }
public DateTime CreateDate { get; set; }
public Guid? CompanyPerson_PersonId { get; set; }
public string CompanyUser_UserId { get; set; }
//Option1: PersonViewModel PersonViewModel {get; set; }
//Option2: public string Title {get;set;}
}
Since I need to show Title of the favorite user in the list (where title belongs to Person class) which way will match with best practices?
Referencing a viewModel from another viewModel or extend viewModel with required extra attributes and fill them in business layer?
After some more research on this topic; I found out at this question
What is ViewModel in MVC?
it is clearly stated that:
View models can combine values from different database entities.
As like below;
So now you have data from the Employees and Departments tables in one
view model. You will just then need to add the following two
properties to your view model and populate it with data:
public int DepartmentId { get; set; }
public IEnumerable<Department> Departments { get; set; }
So I am going with Option 2.
The ViewModel pattern is just one of many patterns that fall into the 'Separated Presentation Pattern' bucket.
It's very important that you think about the requirements of your view before designing the ViewModel. For instance, if you have two widgets in your view and every widget has its own ViewModel, composite ViewModel is suitable in the situation, but if the view is just one that uses multiple domain classes, whether you have View model for each one, composite ViewModel is not suitable because it increases the complexity and every change in one ViewModel can break your code.
Thus, based upon your question
As my domain classes I have Person and FavoritePerson classes.
Since I need to show Title of the favorite user in the list (where title belongs to Person class).
It seems to me that composite ViewModel is not a good choice and you should design a new ViewModel.
It is also worth to read the ViewModel Best Practices

how to pass values from one view to another view

am very new to ASP.NET USING MVC Controllers...so here is my scenario.Am developing an Online Admission system where students come and fill in their required records to be processed for admission.I have different classes that holds specific information about the student.My student class is:
public class Student
{
public int ID { get; set; }
[Required]
public string NAME { get; set; }
[Required]
public string FIRSTNAME { get; set; }
[Required]
public string LASTNAME { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
I have another class called Enrollments where the user Enters all the courses as well as the Grade
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade Grade { get; set; }
public virtual Student Student
{
get;
set;
}
public virtual Course Course { get; set; }
}
public enum Grade
{
A,B,C,D,E,F
}
}
AND different more classes.I HAVE A CONTROLLER called Registration, where i will create the views for each Classes.
SO IN my first View which takes all the student Details,after the Record has been saved.
when the user Clicks next,i want to pass the ID number of the student class to my next view which is the Enrollment View and save the records along with the ID number of the student class which is acting as a foreign key in the enrollment class and database.
Have been trying so hard 2 implement this but with no success.I would appreciate a simple example to demonstrate how to achieve this because am not too good using the mvc framework as i recently started using ASP.NET.
First lets make it clear this is MVC and not web forms. In MVC the flow goes like this
View ----> Controller----->Model then back to controller and so on in usual cases.
Now what you probably want to do is pass a value(here ID ) from the form in first view to another view, this should probably be done like this.
Say for eg. your textbox storing ID is named "tb1" then write the following code in your controller
int id = (Request.Form["tb1"]).toString();
//now we'll store this id in a ViewState varibale like so
ViewData["id"] = id;
//don't worry about the data type of ViewData["id"], it would adapt automatically
Then after proper redirection, i.e. return of the second view from your controller, just access this ViewState variable any where you need like so:
#ViewData["id"]
Please note that this is Razor syntax and your views need to be in .cshtml pages rather than .aspx pages
You Can use ViewBag.MyProp = "XYZ";
and in our view you can retrieve this as :
var name = "#ViewBag.MyProp"

Entitry Framework Code First - > tph -> Foreign key from base class

I have a code first project with some Base classes.
I then have another project that inherits from those classes, adding some more properties, and then generating the DB.
Lets say for example we have a Customer and an Address:
public class Customer
{
[Key]
public int ID { get; set; }
[Required]
[MaxLength(100)]
public string FirstName { get; set; }
}
public class Address
{
[Key]
public int ID { get; set; }
[Required]
[MaxLength(100)]
public string CityName { get; set; }
[Required]
public Customer Customer { get; set; }
}
You'll notice that the Address has a foreign key to Customer.
This all works fine, but what I want to do is Inherit from Customer (or use a partial class) to add another property.
I stall want the database to have an Address and Customer table, but the implementing project should be able to add:
public class Customer : BaseObjects.Customer
{
[Required]
public int PantSize { get; set; }
}
The problem is, that the Base Address returns a Customer in the BaseObjects namespace, not this extended customer class type. So when I say
public DbSet<Customer> Customers { get; set; }
It either complains of having 2 classes with the same simple name (customer), or if I make them partial classes and generate the DBSet in the base DBContext it doesnt include the new property.
How can I do this?
thanks,
James

Validation of nested models in view model in ASP.Net MVC

I have an application with a Company model. The Company model has a navigation property to an Address model (one-to-one relationship):
Company.cs
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
// Snip...
public virtual Address Address { get; set; }
}
I've created a view model to handle the edit, detail, and create actions:
CompanyViewModel.cs
public class CompanyViewModel
{
public int CompanyID { get; set; }
[Required]
[StringLength(75, ErrorMessage = "Company Name cannot exceed 75 characters")]
public string Name { get; set; }
// Snip...
public Address Address { get; set; }
}
I'm using AutoMapper in my controller to map back and forth between the model and view model, and everything is working properly. However, I now want to use validation on the address object - I do not want a company to be created without an address being present.
My first thought was the simple route - I tried putting a '[Required]' annotation on the Address property. This didn't do anything.
I then thought it would be better to do away with the Address property and abstract that data in the view model, so I added properties to the view model for all the properties in my Address class:
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
// etc....
This seemed like good practice, but now my AutoMapper can't map these properties to the Company class' Address object, so I had to manually map in the controller:
public ActionResult Details(int id = 0)
{
// Snip code retrieving company from DB
CompanyViewModel viewModel = new CompanyViewModel();
viewModel.Name = company.Name;
viewModel.Address1 = company.Address.Address1;
// Snip...
return View(viewModel);
}
This leads to a lot of extra code in my controller instead of a nice one-line AutoMapper statement...so what's the right way to deal with this (validation of nested models in a view model)?
Is it good practice to expose the Address property directly in the view model, or better to abstract it out with separate properties like I have done?
Can AutoMapper work in a situation where source and destination are not exact matches?
if you want automapper to be able to map your properties from model to your viewmodel without specifying the mappings explicitly, you've got to use the "flattenting convention" : means that you must concatenate the navigation property's name with its property names.
So your ViewModel should contain
public int CompanyID { get; set; }
[Required]
[StringLength(75, ErrorMessage = "Company Name cannot exceed 75 characters")]
public string Name { get; set; }
// Snip...
//Address is the navigation property in Company, Address1 is the desired property from Address
public string AddressAddress1 { get; set; }
public string AddressAddress2 { get; set; }
public string AddressCity { get; set; }
public string AddressPostalCode { get; set; }
}
by the way, you can also tell AutoMapper to map properties which don't respect the naming convention explicitly :
Mapper.CreateMap<Company, CompanyViewModel>()
.ForMember(dest => dest.Address1, opt => opt.MapFrom(src => src.Address.Address1));

Categories

Resources