This question already has answers here:
Create code first, many to many, with additional fields in association table
(7 answers)
Closed 6 years ago.
I have a many to many relationship defined in my DB between User and Clinic tables. The database wasn't created using EF but I generated the DB model classes using EF. M-M relationship is usually created with EF by having collection object property of the of the linked classes defined within those classes but here I have an indirect relationship. Both User and Clinic models have UserClinic collection object instead of pointing directly to the other class.
Here's how the data objects are defined:
User
public User()
{
this.UserClinics = new HashSet<UserClinic>();
}
public long UsersID { get; set; }
public string AspNetUsersID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Organization { get; set; }
public string Title { get; set; }
public Nullable<System.DateTime> CreateDT { get; set; }
public Nullable<long> CreateBy { get; set; }
public Nullable<System.DateTime> UpdateDT { get; set; }
public Nullable<long> UpdateBy { get; set; }
public string Type { get; set; }
public string LoginID { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserClinic> UserClinics { get; set; }
}
Clinic
public Clinic()
{
this.UserClinics = new HashSet<UserClinic>();
this.Patients = new HashSet<Patient>();
}
public long ClinicID { get; set; }
public Nullable<long> NetworkID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public Nullable<System.DateTime> CreateDT { get; set; }
public Nullable<long> CreateBy { get; set; }
public Nullable<System.DateTime> UpdateDT { get; set; }
public Nullable<long> UpdateBy { get; set; }
public virtual Network Network { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserClinic> UserClinics { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Patient> Patients { get; set; }
}
UserClinic
public partial class UserClinic
{
public long UsersID { get; set; }
public long ClinicID { get; set; }
public Nullable<System.DateTime> CreateDT { get; set; }
public Nullable<long> CreateBy { get; set; }
public Nullable<System.DateTime> UpdateDT { get; set; }
public Nullable<long> UpdateBy { get; set; }
public virtual Clinic Clinic { get; set; }
public virtual User User { get; set; }
}
What's the best way to query objects so I get something to the effect of:
var cliniclist = user.clinics.toList();
or
var user.clinics.Add(clinicList);
To select you just need to select the UserClinics collection and then select the Clinic property from it:
var clinics = user.UserClinics.Select(x => x.Clinic);
To add:
user.UserClinics.Add(new UserClinic { ClinicID = 1, Clinic = new Clinic { ... } });
Related
I am building a holiday tracking website.
I have two data connections in my mvc application.
DeafultConnection which contains aspnetusers which I am using for user logins and Registrations.
Then LotusWorksEntities which I am using to track Employee details such as holiday requests, hours taking etc.
In DefaultConnections under aspnetusers, there's a column for email.
In LotusWorksEntitles under Employee Table, there's also a column for email.
On my Admin view page, I have a list of all Employees which has a column for Site.
I want Admins who have been assigned certain sites to only see employees from those assigned sites.
I have done this manually by
public ActionResult Index()
{
var employees = db.Employees.Include(e => e.Area).Include(e => e.Discipline).Include(e => e.Shift).Include(e => e.Site).Where(e => e.SiteID == 2);
return View(employees.ToList());
}
Is there a way that I could connect these two connections, so that when an admin logs in, it knows what site they've been assigned to and displays those employees under that site.
Here are my models:
public partial class Employee
{
public int EmployeeID { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public System.DateTime StartDate { get; set; }
public int RoleID { get; set; }
public int ShiftID { get; set; }
public int AreaID { get; set; }
public int DisciplineID { get; set; }
public int SiteID { get; set; }
public int ALCategory { get; set; }
public int HoursTaken { get; set; }
public Nullable<int> AwardedLeave { get; set; }
public Nullable<int> TotalHoursThisYear { get; set; }
public int HoursCarriedForward { get; set; }
public Nullable<int> EntitlementRemainingThisYear { get; set; }
public string Comments { get; set; }
public int SickLeaveTaken { get; set; }
public Nullable<int> SickLeaveEntitlement { get; set; }
public Nullable<int> SickLeaveEntitlementRemaining { get; set; }
public int StudyLeaveEntitlement { get; set; }
public int StudyLeaveTaken { get; set; }
public Nullable<int> StudyLeaveRemaining { get; set; }
public int ExamLeaveTaken { get; set; }
public int ForceMajeure { get; set; }
public int BereavementLeaveTaken { get; set; }
public int MaternityLeaveTaken { get; set; }
public int ParentalLeaveTaken { get; set; }
public int AdoptionLeaveTaken { get; set; }
public string ManagerEmail { get; set; }
public string AreaManagerEmail { get; set; }
public virtual Area Area { get; set; }
public virtual Discipline Discipline { get; set; }
public virtual Shift Shift { get; set; }
public virtual Site Site { get; set; }
}
Then my Site Model is:
public partial class Site
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Site()
{
this.Employees = new HashSet<Employee>();
}
public int SiteID { get; set; }
public string SiteName { get; set; }
public string SiteManager { get; set; }
public string SiteDelegate { get; set; }
public string SiteAdmin { get; set; }
public string SiteLocation { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Employee> Employees { get; set; }
}
Employee Table and Site Table are connected through a foreign key.
Not completely understood which two connections you have is it database connection you are talking about?
But anyways you can use Linq joins to connect two separate list of objects in C#. filter data. Basically your two list should have some relation for join to work.
Here it is explained how to join two list in memory.
I will appreciate if somebody can tell me why entity framework is not creating join table for following model. It is creating table for type and feature but not the table that will join them.
public class DeviceType
{
[Display(Name = "ID")]
public int DeviceTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<DeviceFeature> DeviceFeatures { get; set; }
}
public class DeviceFeature
{
[Display(Name = "ID")]
public int DeviceFeatureID { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<DeviceType> DeviceTypes { get; set; }
}
public class DeviceFeatureView
{
public virtual IEnumerable<DeviceType> DeviceTypes { get; set; }
public virtual IEnumerable<DeviceFeature> DeviceFeatures { get; set;
}
You do not need the bridge to create a many-to-many relationship. EF will figure it out. Change the type of the navigation properties from IEnumerable to ICollection like this:
public class DeviceType
{
public DeviceType()
{
this.DeviceFeatures = new HashSet<DeviceFeature>();
}
[Display(Name = "ID")]
public int DeviceTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<DeviceFeature> DeviceFeatures { get; set; }
}
public class DeviceFeature
{
public DeviceFeature()
{
this.DeviceTypes = new HashSet<DeviceType>();
}
[Display(Name = "ID")]
public int DeviceFeatureID { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public ICollection<DeviceType> DeviceTypes { get; set; }
}
More about it here.
I am trying to add an entry to a table that holds a users browsing history information. However, when trying to save the addition an SqlException is thrown:
Cannot insert duplicate key row in object 'dbo.AspNetUsers' with
unique index 'UserNameIndex'. The duplicate key value is
(exampleUserName). The statement has been terminated.
A user is has many browsing histories but a browsing history can only be attached to one user so there is a user as part of the BrowsingHistory DataModel:
namespace DataModels
{
[Table("BrowsingHistory")]
public class BrowsingHistory
{
[Key]
public int BrowsingHistoryId { get; set; }
public int ProductId { get; set; }
public System.DateTime DateTime { get; set; }
public int DeviceId { get; set; }
public int UserId { get; set; }
public virtual AspNetUsers User { get; set; }
public virtual Device Device { get; set; }
public virtual Product Product { get; set; }
}
}
It is to note that I am using the Microsoft Identity classes for my authentication. The user class looks as follows:
namespace DataModels
{
using System;
using System.Collections.Generic;
[Table("AspNetUsers")]
public class AspNetUsers
{
public AspNetUsers()
{
BrowsingHistories = new HashSet<BrowsingHistory>();
Orders = new HashSet<Order>();
AspNetUserClaims = new HashSet<AspNetUserClaims>();
AspNetRoles = new HashSet<AspNetRoles>();
}
[Key]
public int Id { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public DateTime? LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string UserName { get; set; }
public string HouseName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string Town { get; set; }
public string County { get; set; }
public string Postcode { get; set; }
public string ContactNumber { get; set; }
public virtual ICollection<BrowsingHistory> BrowsingHistories { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual ShoppingCart ShoppingCart { get; set; }
public virtual ICollection<AspNetUserClaims> AspNetUserClaims { get; set; }
public virtual ICollection<AspNetRoles> AspNetRoles { get; set; }
}
}
The error occurs when trying to save the addition in the repository. On the _context.SaveChanges() line the method below.
public void CreateBrowsingHistoryEntry(BrowsingHistory bhe)
{
_context.BrowsingHistory.Add(bhe);
_context.SaveChanges();
}
Any help with this issue would be greatly appreciated.
I am completely new to ASP.NET and was trying to cross-reference two different models with each other. I have 'Customer':
public class Customer
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string Zipcode { get; set; }
public string City { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
and 'Reservation':
public class Reservation
{
public int ReservationID { get; set; }
public string PetName { get; set; }
public DateTime Birthdate { get; set; }
public string Specie { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public Customer Customer { get; set; }
}
Now, each Reservation should belong to a Customer (as you can see in the bottom line of the Reservation model) and should therefore contain the CustomerID. On the other hand should each Customer contain references to each Reservation that was made by him.
How can I setup this relation?
Use an ICollection for a one to many relationship.
public class Customer
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string Zipcode { get; set; }
public string City { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public ICollection<Reservation> Reservations { get; set; }
}
Note I originally suggested a generic list, but there's a few subtle differences.
I am having trouble with SQL Server creating Foreign Key constraints when using Entity Framework Code First.
This is my scenario. I am building an application which allows us to log tickets against any of our systems and automatically assign the ticket to the relevant person.
We have Services, which can have many categories. The categories can have many subcategories. A help desk person can be assigned to Service, and Category or Subcategory.
Here are my classes:
Service.cs
public class Service
{
[Key]
public int ServiceID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
public HelpDeskMember CreatedBy { get; set; }
public DateTime? DeletedDate { get; set; }
public HelpDeskMember DeletedBy { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subcategory> Subcategories { get; set; }
public virtual ICollection<HelpDeskMember> LinesOfSupport { get; set; }
}
Category.cs
public class Category
{
[Key]
public int CategoryID { get; set; }
[ForeignKey("Service")]
public int ServiceID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
public HelpDeskMember CreatedBy { get; set; }
public DateTime? DeletedDate { get; set; }
public HelpDeskMember DeletedBy { get; set; }
public virtual Service Service { get; set; }
public virtual ICollection<Subcategory> Subcategories { get; set; }
public virtual ICollection<HelpDeskMember> LinesOfSupport { get; set; }
}
Subcategory.cs
public class Subcategory
{
[Key]
public int SubcategoryID { get; set; }
[ForeignKey("Service")]
public int ServiceID { get; set; }
[ForeignKey("Category")]
public int CategoryID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
public HelpDeskMember CreatedBy { get; set; }
public DateTime? DeletedDate { get; set; }
public HelpDeskMember DeletedBy { get; set; }
public virtual Service Service { get; set; }
public virtual Category Category { get; set; }
public virtual ICollection<HelpDeskMember> LinesOfSupport { get; set; }
}
and finally HelpDeskMember.cs
public class HelpDeskMember
{
public int HelpDeskMemberID { get; set; }
public string Name { get; set; }
public bool Admin { get; set; }
public bool Available { get; set; }
public DateTime? CreatedDate { get; set; }
public DateTime? LastLogin { get; set; }
public DateTime? DeletedDate { get; set; }
public DateTime? DeletedBy { get; set; }
public virtual ICollection<Service> Services { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subcategory> Subcategories { get; set; }
}
When the Database is being initialised, I am getting the following error message:
Introducing FOREIGN KEY constraint 'Subcategory_Service' on table 'Subcategories' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
I'm guessing the problem is with how I have defined the Key's and ForeignKey's. Any help appreciated. Thanks.
Depending on your needs. You can in configuration for your entity use WillCascadeOnDelete(false)1 or globally removing OneToManyCascadeDeleteConvention2.
Both can be set in OnModelCreating using ModelBuilder input parameter.