Many to Many Relationship in MVC 5 EF6 - asp.net-mvc

Im using MVC 5 and EF 6.
There are 3 tables in my code: "Leads", "Phones", "LeadStatus" and a junction table "LeadPhones".
I want to show following properties in Index View:
Leads.FullName
LeadStatus.Status
Phones.PhoneID
How should I configure the LeadController?
public partial class Leads
{
public Leads()
{
this.LeadPhones = new HashSet<LeadPhones>();
}
[Key]
public int LeadID { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return NamePrefix + " " + FirstName + " " + LastName; } }
public int LeadStatusID { get; set; }
public virtual LeadStatus LeadStatus { get; set; }
public virtual ICollection<LeadPhones> LeadPhones { get; set; }
}
and
public partial class Phones
{
public Phones()
{
this.AccountPhones = new HashSet<AccountPhones>();
this.ContactPhones = new HashSet<ContactPhones>();
this.EmployeePhones = new HashSet<EmployeePhones>();
this.LeadPhones = new HashSet<LeadPhones>();
}
[Key]
public int PhoneID { get; set; }
public string PhoneNo { get; set; }
public virtual ICollection<LeadPhones> LeadPhones { get; set; }
}
and
public partial class LeadPhones
{
[Key]
public int LeadPhoneID { get; set; }
public int LeadID { get; set; }
public int PhoneID { get; set; }
public virtual Leads Leads { get; set; }
public virtual Phones Phones { get; set; }
}
and
public partial class LeadStatus
{
public LeadStatus()
{
this.Leads = new HashSet<Leads>();
}
[Key]
public int LeadStatusID { get; set; }
public string Status { get; set; }
public virtual ICollection<Leads> Leads { get; set; }
}
the following does not work:
public ActionResult Index()
{
var leads = db.Leads.Include(l => l.LeadStatus).Include(l => l.LeadPhones);
return View(leads);
}
The main problem is the "PhoneNo". How could I get that from a junction table?

Remove the LeadPhoneID column from the LeadPhones table -- It isn't necessary and will only cause problems for you. Remove all references to LeadPhones in your classes. Leads a virtual property to Phones (not LeadPhones). LeadPhones has a virtual property to Leads (not LeadPhones).
After you do that, then you should be able to:
var leads = db.Leads.Include(l => l.LeadStatus).Include(l => l.Phones);
public partial class Lead
{
public Lead()
{
this.Phones = new HashSet<Phone>();
}
[Key]
public int LeadID { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return NamePrefix + " " + FirstName + " " + LastName; } }
public int LeadStatusID { get; set; }
public virtual LeadStatus LeadStatus { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
public partial class Phone
{
public Phone()
{
this.AccountPhones = new HashSet<AccountPhones>();
this.ContactPhones = new HashSet<ContactPhones>();
this.EmployeePhones = new HashSet<EmployeePhones>();
this.Leads = new HashSet<Lead>();
}
[Key]
public int PhoneID { get; set; }
public string PhoneNo { get; set; }
public virtual ICollection<Lead> Leads { get; set; }
}
public partial class LeadStatus
{
public LeadStatus()
{
this.Leads = new HashSet<Lead>();
}
[Key]
public int LeadStatusID { get; set; }
public string Status { get; set; }
public virtual ICollection<Lead> Leads { get; set; }
}
I've also corrected the plurality of your classes. Lead vs Leads. The class describes a single lead, so it should be called Lead not Leads. Phone vs Phones.

Related

AutoMapper Many to Many relationship

I'm not sure where I'm going wrong here. I want to map my classes so that there aren't extra levels in the returned values.
Models (DTOs):
public class FilmViewModel
{
public FilmViewModel() { }
public int Id { get; set; }
[Required(ErrorMessage = "Naziv filma je obavezno polje.")]
public string Naziv { get; set; }
public string Opis { get; set; }
public string UrlFotografije { get; set; }
[RegularExpression(#"^(19|20)[\d]{2,2}$", ErrorMessage = "Godina mora biti u YYYY formatu.")]
public int Godina { get; set; }
public JezikEnum Jezik { get; set; }
public int Trajanje { get; set; }
public bool IsActive { get; set; }
public List<Licnost> Licnosti { get; set; }
}
public class LicnostViewModel
{
public LicnostViewModel() { }
public int Id { get; set; }
[Required]
public string ImePrezime { get; set; }
[Required]
public bool IsGlumac { get; set; }
[Required]
public bool IsRedatelj { get; set; }
public List<Film> Filmovi { get; set; }
}
Entities:
public class Film
{
[Key]
public int Id { get; set; }
[Required]
public string Naziv { get; set; }
public string Opis { get; set; }
public string UrlFotografije { get; set; }
[RegularExpression(#"^(19|20)[\d]{2,2}$")]
public int Godina { get; set; }
public JezikEnum Jezik { get; set; }
public bool IsActive { get; set; }
public int Trajanje { get; set; }
public List<FilmLicnost> Licnosti { get; set; }
}
public class Licnost
{
[Key]
public int Id { get; set; }
[Required]
public string ImePrezime { get; set; }
[Required]
public bool IsGlumac { get; set; }
[Required]
public bool IsRedatelj { get; set; }
public List<FilmLicnost> Filmovi { get; set; }
}
public class FilmLicnost
{
[Key]
public int Id { get; set; }
[ForeignKey(nameof(Licnost))]
public int LicnostId { get; set; }
public Licnost Licnost { get; set; }
[ForeignKey(nameof(Film))]
public int FilmId { get; set; }
public Film Film { get; set; }
}
Basically Swagger already shows me what I'm returning, but I want to avoid unnecessary nesting. It's marked in the image:
I want to say that I've been looking all over SO, AutoMapper documentation etc. No answer/example finds me the solution I need. I'm either missing a Model(DTO) somewhere or there is something major wrong with my logic.
Some example links that I tried are this and this
Also here are some links I tried to get information from: link1, link2
This is what I've tried so far:
CreateMap<FilmLicnost, LicnostViewModel>()
.ForMember(dest => dest.Filmovi, dest => dest.MapFrom(x => x.Film))
.AfterMap((source, destination) =>
{
if (destination?.Filmovi == null) return;
foreach (var temp in destination.Filmovi)
{
temp.Id = source.Film.Id;
temp.IsActive = source.Film.IsActive;
temp.Jezik = source.Film.Jezik;
temp.Naziv = source.Film.Naziv;
temp.Opis = source.Film.Opis;
temp.Godina = source.Film.Godina;
temp.Trajanje = source.Film.Trajanje;
temp.UrlFotografije = source.Film.UrlFotografije;
}
});
CreateMap<FilmLicnost, FilmViewModel>()
.ForMember(dest => dest.Licnosti, dest => dest.MapFrom(x => x.Licnost))
.AfterMap((source, destination) =>
{
if (destination?.Licnosti == null) return;
foreach (var temp in destination?.Licnosti)
{
temp.Id = source.Licnost.Id;
temp.ImePrezime = source.Licnost.ImePrezime;
temp.IsGlumac = source.Licnost.IsGlumac;
temp.IsRedatelj = source.Licnost.IsRedatelj;
}
});
Also this:
CreateMap<FilmLicnost, Film>()
.ForMember(dest => dest.Licnosti, dest => dest.Ignore());
CreateMap<FilmLicnost, Licnost>()
.ForMember(dest => dest.Filmovi, dest => dest.Ignore());
Note I have already defined the mapping for Entities:
CreateMap<Film, FilmViewModel>();
CreateMap<FilmViewModel, Film>();
CreateMap<Licnost, LicnostViewModel>();
CreateMap<LicnostViewModel, Licnost>();

NullReferenceException in a three table model in Entity Framework

I'm trying to join three tables in a view model. It works with two tables but crashes when I add a third. Here are the models and the controller. The models section_detail, phone, and department were generated by Entity Framework.
EmployeeViewModel was created by copying properties from the other models. I've abbreviated some of the models shown here with:
public partial class section_detail
{
public int section_detail_id { get; set; }
public Nullable<int> parent_section_det_id { get; set; }
. . .
public string Comments { get; set; }
public string email { get; set; }
public virtual department department { get; set; }
public virtual phone phone { get; set; }
}
public partial class phone
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public phone()
{
this.section_detail = new HashSet<section_detail>();
}
public int phone_id { get; set; }
public string area_code { get; set; }
public string phone_nbr { get; set; }
. . .
public string activity_code { get; set; }
public string function_code { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<section_detail> section_detail { get; set; }
public virtual BudgetUnit BudgetUnit { get; set; }
}
public partial class department
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public department()
{
this.section_detail = new HashSet<section_detail>();
}
public int dept_id { get; set; }
public string description { get; set; }
public string cost_center_code { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<section_detail> section_detail { get; set; }
}
public class EmployeeViewModel
{
public int section_detail_id { get; set; }
public Nullable<int> parent_section_det_id { get; set; }
public Nullable<byte> page_code { get; set; }
public string cost_center_code { get; set; }
public string print_descrip { get; set; }
public Nullable<int> phone_id { get; set; }
public Nullable<int> employee_id { get; set; }
public static explicit operator EmployeeViewModel(List<section_detail> v)
{
throw new NotImplementedException();
}
public string first_name { get; set; }
. . .
public string Comments { get; set; }
public string email { get; set; }
public string description { get; set; }
public string area_code { get; set; }
public string phone_nbr { get; set; }
public string BU { get; set; }
}
Controller:
private vcpds_test1Entities db = new vcpds_test1Entities();
// GET: EmployeeList
public ActionResult Index()
{
List<section_detail> employeeList = db.section_detail.ToList();
List<EmployeeViewModel> employeeVMList = employeeList.Where(emp => emp.page_code == 3)
.Select(emp => new EmployeeViewModel
{
last_name = emp.last_name,
first_name = emp.first_name,
employee_id = emp.employee_id,
phone_nbr = "(" + emp.phone.area_code + ") " + emp.phone.phone_nbr.Substring(0, 3) + "-" + emp.phone.phone_nbr.Substring(3, 4),
BU = emp.phone.BU,
description = emp.department.description,
page_code = emp.page_code
}).OrderBy(emp => emp.last_name).ThenBy(emp => emp.first_name).ToList();
return View(employeeVMList);
}
I get these messages:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
VCPDS2.Models.section_detail.department.get returned null.
If I comment out description = emp.department.description from the controller, then it will return data from the section_detail and phone tables. I've checked the database and the relationships seem ok. I've tried refreshing the models from the database with no change.
It's possible that a emp doesn't have a department so it in itself is null. Description can't be a property of a null. So, what you can simply do is check if it is null first by using null operator:
...
//description = emp.department.description,
description = emp.department?.description ?? "",
...
Basically, if department itself is null, it will stop checking right there, and the ?? shortcut is to use the statement on the right side which is "" if the statement on the left is null.
If you were not expecting an emp not to have a department, you may need to revise your query
Quick edit: You probably need to use an Include in your query so it can bring the department's properties (for description):
List<section_detail> employeeList = db.section_detail
.Include(x => x.department)
.ToList();

EnumerableExtensions.Join inaccessible due to its protection level

am getting a Enumerable Extensions join is inaccessible due to its protection level error. I am using EF Core for database connections. How to perform joins using LINQ ??
var seatBookings =(
from sb in Context.SeatBookings
join bd in Context.BookingDetails on sb.BookingId
equals bd.Id
where bd.ShowId == showId
select sb
).ToList();
public partial class SeatBookings
{
public int Id { get; set; }
public int? BookingId { get; set; }
public int SeatNumber { get; set; }
public BookingDetails Booking { get; set; }
}
public partial class BookingDetails
{
public BookingDetails()
{
SeatBookings = new HashSet<SeatBookings>();
}
public int Id { get; set; }
public int ShowId { get; set; }
public string Email { get; set; }
public string MobileNumber { get; set; }
public int TheaterId { get; set; }
public int BookedSeatsCount { get; set; }
public ShowDetails Show { get; set; }
public ICollection<SeatBookings> SeatBookings { get; set; }
}

MVC Many to many search

i have three tables in my model class
public class Objekat
{
[Key]
public int ObjekatID { get; set; }
[Display(Name="Naziv Objekta")]
public String Naziv { get; set; }
public int? KategorijaID { get; set; }
public int[] idZanrova { get; set; }
public virtual ICollection<Zanr> Zanr { get; set; }
public virtual Kategorija Kategorija { get; set; }
}
public class Zanr
{
public int ZanrID { get; set; }
[Display(Name="Naziv Zanra")]
public string Naziv { get; set; }
public virtual ICollection<Objekat> Objekat { get; set; }
}
public class Kategorija
{
public int KategorijaID { get; set; }
public string Naziv { get; set; }
public ICollection<Objekat> Objekat { get; set; }
}
public class KatalogContext : DbContext
{
public DbSet<Objekat> Objekti { get; set; }
public DbSet<Zanr> Zanrovi { get; set; }
public DbSet<Kategorija> Kategorije { get; set; }
public KatalogContext() : base("MojaBaza") { }
}
Is it possible to make a filter for showing only data from table "Objekat" witch contains specific "Zanrs"?
I suppose the relation between tables "Objekat" and "Zanr" are ok ?

Passing multiple models into view MVC

Relatively new to MVC and can't figure out how to pass data from multiple models into a single view. I know I need to use a view model, but I can't figure out what to do in the controller.
Models:
public class Child
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ChartNumber { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
public string City { get; set; }
public string State { get; set; }
[Display(Name = "Zip Code")]
public int ZipCode { get; set; }
public string Ethnicity { get; set; }
public string Referral { get; set; }
[Display(Name = "Recommended Re-evaluation")]
public bool ReEval { get; set; }
[Display(Name = "Hearing Aid Candidate")]
public bool HaCandidate { get; set; }
[Display(Name = "Fit With Hearing Aid")]
public bool FitHa { get; set; }
public virtual List<ChildEval> ChildEvals { get; set; }
}
public class ChildEval
{
[Key]
public int ChildEvalId { get; set; }
public DateTime Date { get; set; }
public int PtaRight { get; set; }
public int PtaLeft { get; set; }
public int UnaidedSiiRight { get; set; }
public int UnaidedSiiLeft { get; set; }
public int AidedSiiRight { get; set; }
public int AidedSiiLeft { get; set; }
public int ChartNumber { get; set; }
public virtual Child Child { get; set; }
}
}
DbContext
public class UnitedContext : DbContext
{
public UnitedContext() : base("name=UnitedContext")
{
}
public System.Data.Entity.DbSet<United.Models.Child> Children { get; set; }
public System.Data.Entity.DbSet<United.Models.ChildEval> ChildEvals { get; set; }
}
ViewModel:
public class ChildViewModel
{
public class Child
{
public string FirstName { get; set; }
}
public class ChildEval
{
public int PtaRight { get; set; }
}
}
ViewModelController? :
public class ViewModelController : Controller
{
//
// GET: /ViewModel/
public ActionResult Index()
{
return View();
}
}
}
I'm stuck on how to create the controller for the viewmodel and how to actually get the data into the view. Any help would be greatly appreciated!
Don't have a controller called ViewModelController. Controller is the handler between database and the view. Therefore the name of the controller should tell the programmer what kind of data the controller is controlling. By default, it also indicates the subsite you are in your web application ( ViewModelController would yield http://mysite/ViewModel/ ).
Since you are handling children, I'm calling it ChildrenController for now.
Generally a good idea is to wrap your 2 models into one viewmodel and work with that. In this case Model != ViewModel, model is the database model of the entity while ViewModel is the one that's passed to/from the view.
public class Child
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class SomeOtherModel
{
public int ID { get; set; }
public int SomeInteger { get; set; }
public int SomeOtherInteger { get; set; }
}
public class ChildViewModel
{
public Child Child { get; set; }
public SomeOtherModel SomeOtherModel { get; set; }
public ChildViewModel(Child child, SomeOtherModel s)
{
Child = child;
SomeOtherModel = s;
}
}
In your controller
public class ChildrenController : Controller
{
//
// GET: /Children/
public ActionResult Index()
{
Child child = /*Fetch the child from database*/;
SomeOtherModel someOther = = /*Fetch something else from database*/;
ChildViewModel model = new ChildViewModel(child,someOther);
return View(model);
}
}
View:
#model ChildViewModel
#Html.EditorFor(model => model.Child.FirstName)
#Html.EditorFor(model => model.Child.LastName)

Resources