Map same Model class for multiple purposes in Entity FrameWork - c#

I have two model classes one is ApplicationUser and the second is Appointment. Application user includes all users that use the application, in my case, Doctors and Data entry operators. Doctors will be assigned to each appointment and Data entry operators will be making this log to DB. I want to map both these users with appointment. I have tried something like this
public class Appointment
{
public int AppointmentID { get; set; }
public DateTime Date { get; set; }
public int DoctorID { get; set; }
[ForeignKey("DoctorID")]
public virtual ApplicationUser Doctor { get; set; }
public int SystemUserID { get; set; }
public virtual ApplicationUser SystemUser { get; set; }
}
public class ApplicationUser : IdentityUser
{
public string Email { get; set; }
public string Mobile { get; set; }
public string FirstNsme { get; set; }
public string LastName { get; set; }
}
But this throws an error
Appointment_Doctor_Target_Appointment_Doctor_Source: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'DoctorID' on entity 'Appointment' does not match the type of property 'Id' on entity 'ApplicationUser' in the referential constraint 'Appointment_Doctor'.
Can anyone point out why this error is occurring and what is the correct approach to this problem?

IdentityUser as all entities in asp.net identity entity framework have string as key. You are trying to map to an int. So either use Guids as foreign keys in your Appointment entity
public class Appointment
{
[Key]
public int AppointmentID { get; set; }
public DateTime Date { get; set; }
public string DoctorID { get; set; }
[ForeignKey("DoctorID")]
public virtual ApplicationUser Doctor { get; set; }
public string SystemUserID { get; set; }
[ForeignKey("SystemUserID ")]
public virtual ApplicationUser SystemUser { get; set; }
}
or change the type of Ids in identity classes to int. You can find help here.

There are multiple issue in your classes.
What is DoctorID? Where it is defined?
You need to first focus on establishing correct relationship between your entities logically.
I think your Appointment class need not contain SystemUserID who added an appointment.
Second if you wanted to share some properties between two user types than create a common class and derive in Doctor and SystemUser.
Add DoctorId into Doctor table along with specific details pertaining to Doctor e.g. Specialty.
SystemUser adds a appointment so the table should contain data related to that i.e. doctorId and appointmentId.
Update:
Based on your comment, you could do something like this. Note its for reference only, you are better person to define a better DB Schema.
public class Appointment
{
public int AppointmentID { get; set; }
public DateTime Date { get; set; }
public int DoctorID { get; set; }
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser Doctor { get; set; }
public int SystemUserID { get; set; }
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser SystemUser { get; set; }
}
public class ApplicationUser
{
public int ApplicationUserId { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public string FirstNsme { get; set; }
public string LastName { get; set; }
public UserType UserType { get; set; }
}
public enum UserType
{
Doctor,
SystemUser
}

FURTHER AND MORE COMPLEX ERROR:
I had this error multiple times across 4 linked tables.
Each table had composite keys of 3 - 7 fields,
and one table referenced its own 3-field key with a different mix of its own columns.
I struggled for ages with fixing one sequence of fields (which does fix the error as mentioned in other posts) only to have knock-on effect in other entities.
The solution:
Align all linked tables' FK fields in order of reducing occurrence
ORIGINALLY:
AFTER KEY FIELDS WERE ALIGNED:
And re-ordered all anonymous FK objects in FluentAPI in the DbContext to match the new order.
This fixed all headaches.

Related

EF 6 getting parent record from DB when table has many to many relation with itself

I am trying to build an organization hierarchy where each team might contain one or many members and/or one or many sub-teams.
To do so, my model is:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Members { get; set; }
public virtual ICollection<Team> SubTeams { get; set; }
public Employee Manager { get; set; }
}
When adding a migration and updating database, everything seems logical in the table.
EF has added an extra nullable column "Team_Id" where the Id of the parent Team gets stored.
My question is about getting the Id of the parent Team from my model.
I tried adding:
public int? Team_Id
To my model, but EF considered it as a model change and asked for another migration.
How can I get the value of column Team_Id in my model? getting this info takes too much processing when looping through teams.
I always add foreign key in my model. When it adds to the model, EF won't add Team_Id .
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Members { get; set; }
public virtual ICollection<Team> SubTeams { get; set; }
public Employee Manager { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public Team ParentTeam { get; set; }
}
I hope this example be helpful.

Different user types with ASP.NET Core 1.1 Identity and Entity Framework Core

Using ASP.NET Core Identity with Entity framework Core i need to add different types of users in my app:
Let's say that i need two types of users: "Student" and "Teacher"; both of them are also ApplicationUsers since they have to be authenticated to access the app.
I have accomplish that creating two tables: one for Student and one for Teacher. Both tables are one-to-one related with the ApplicationUser table.
I'd like to know if this is correct or if i'm doing something wrong, because when updating the database with migrations it throws the error "FOREIGN KEY 'FK_Student_AspNetUsers_Id' in 'Student' table may cause cycles or multiple cascade paths. specify ON DELETE NO ACTION or UPDATE NO ACTION". And, in any case, if it goes right, at the end i'd have an ApplicationUser class with two columns (one for StudentId and another for TeacherId), and one of them will always be null since an ApplicationUser can be a Student or a Teacher, but not both.
Here is my code so far:
public class ApplicationUser : IdentityUser<int>
{
public string Name { get; set; }
[ForeignKey("Teacher")]
public int? TeacherId { get; set; }
public virtual Teacher Teacher { get; set; }
[ForeignKey("Student")]
public int? StudentId { get; set; }
public virtual Student Student { get; set; }
}
public class Student
{
[Key, ForeignKey("User")]
public int Id { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
public string MotherMaidenName { get; set; }
public DateTime BirthDate { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ApplicationUser User { get; set; }
}
public class Teacher
{
[Key,ForeignKey("User")]
public int Id { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
public string MotherMaidenNAme { get; set; }
public virtual ApplicationUser User { get; set; }
}
UPDATED: I've set TeacherId and StudentId as nullable, so the Error mentioned above is gone.
You shouldn't create different tables for each user type you have.
You should create roles and assign that roles to a user. For example create a role student and a role teacher and assign them acording to your needs.
So I would say what you've done isn't a good design.
When you need to save additional values for a student/teacher than I would do something similar to your design.
But I wouldn't add ID's for my student/teacher to my ApplicationUser class.
I would simply add a UserId to my student/teacher class.
So the design issue should be that you're trying to put that stuff into the ApplicationUser class.

Unable to determine the principal end of an association - Entity Framework Model First

I have created Entity Data Model in Visual Studio. Now I have file with SQL queries and C# classes generated from Model.
Question:
Classes are generated without annotations or code behind (Fluent API). Is it OK? I tried to run my application but exception was thrown:
Unable to determine the principal end of an association between the types 'Runnection.Models.Address' and 'Runnection.Models.User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I read that I can not use Fluent API with "Model First". So what can I do?
Code:
User
public partial class User
{
public User()
{
this.Events = new HashSet<Event>();
this.CreatedEvents = new HashSet<Event>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Photo { get; set; }
public int EventId { get; set; }
public string Nickname { get; set; }
public OwnerType OwnerType { get; set; }
public NetworkPlaceType PlaceType { get; set; }
public virtual ICollection<Event> Events { get; set; }
public virtual Address Address { get; set; }
public virtual ICollection<Event> CreatedEvents { get; set; }
public virtual Owner Owner { get; set; }
}
Address
public partial class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
Context
//Model First does not use this method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>().HasRequired(address => address.User)
.WithRequiredDependent();
modelBuilder.Entity<User>().HasRequired(user => user.Address)
.WithRequiredPrincipal();
base.OnModelCreating(modelBuilder);
}
You have to specify the principal in a one-to-one relationship.
public partial class Address
{
[Key, ForeignKey("User")]
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
By specifying a FK constraint, EF knows the User must exists first (the principal) and the Address follows.
Further reading at MSDN.
Also, see this SO answer.
Updated from comments
In the designer, select the association (line between Users & Address). On the properties window, hit the button with the [...] on Referential Constraint (or double click the line). Set the Principal as User.
Error:
Had same error of "Unable to determine the principal end of an association between the types 'Providence.Common.Data.Batch' and 'Providence.Common.Data.Batch'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.".
HOWEVER, note that this is the SAME table.
Cause: My database was MS SQL Server. Unfortunately when MS SQL Server's Management Studio adds foreign keys, it adds the default foreign key as Batch ID column of Batch table linking back to itself. You as developer are suppose to pick another table and id to truly foreign key to, but if you fail to it will still allow entry of the self referencing FK.
Solution:
Solution was to delete the default FK.
Cause 2: Another situation is that the current table may be fixed but the old historical image of the table when the EF's edmx was done had the default FK.
Solution 2: is to delete the table from the Model Browser's Entity Types list and click "yes" and then "Update Model from the Database" again.

Two foreign keys with same Navigation Property?

I am new to Entity Framework so I don't know much about it. Currently I am working on My College Project, in that Project I came across a problem where I have two foreign keys refers to the Same column in another table. how can I handle this situation.
Is it necessary to create Navigation Property for Every Foreign key. And if I create another Navigaton property for ContactId then it is necessary to create another Navigation Property in User class like:
public virtual ICollection<BlockedUser> SomePropertyName { get; set; }
please tell me the best way to overcome this problem. I am using Entity Framework 6.
Here are My Model Classes:
public class BlockedUser
{
// User Foreign Key
public int UserId { get; set; } // Composite Primary Key
// User Foreign key
public int ContactId { get; set; } // Composite Primary Key
// User Navigation Property
public virtual User User { get; set; }
}
public class User
{
public int UserId { get; set; } // Primary key
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
// BlockedUser Navigation Property
public virtual ICollection<BlockedUser> BlockedUsers { get; set; }
}
Is it necessary to create Navigation Property for Every Foreign key?
Yes, or more precisely: You need at least one navigation property for every relationship. "At least one" means that you can decide which of the two entities you want to add the navigation property to. It normally depends on the most common use cases in your application if you often want to navigate from entity A to entity B or the other way around. If you want, you can add the navigation properties to both entities but you don't need to.
In your model you apparently have two (one-to-many) relationships. If you want to expose navigation properties in both entities you would need four navigation property and - important! - you have to define which navigation properties form a pair for a relationship (see the [InverseProperty] attribute in the following code snippet).
With data annotations it would like this:
public class BlockedUser
{
[Key, ForeignKey("User"), Column(Order = 1)]
public int UserId { get; set; }
[Key, ForeignKey("Contact"), Column(Order = 2)]
public int ContactId { get; set; }
[InverseProperty("BlockedUsers")]
public virtual User User { get; set; }
[InverseProperty("BlockedContacts")]
public virtual User Contact { get; set; }
}
public class User
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public virtual ICollection<BlockedUser> BlockedUsers { get; set; }
public virtual ICollection<BlockedUser> BlockedContacts { get; set; }
}
If you don't want the BlockedContacts collection you can probably just remove it and the [InverseProperty("BlockedContacts")] attribute from the Contact navigation property as well.
You could use attribute ForeignKey to solve your problem. ForeignKey is used to pair navigation property and foreign key property.There is no difference between FK data annotation with Foreign Key property and FK with Navigation Properties. However, the following code will create two foreign keys with different name.
public class BlockedUser
{
// User Foreign Key
[ForeignKey("UserId")]
public int UserId { get; set; } // Composite Primary Key
// User Foreign key
[ForeignKey("BlockedUser_User")]
public int ContactId { get; set; } // Composite Primary Key
// User Navigation Property
public virtual User User { get; set; }
}
public class User
{
public int UserId { get; set; } // Primary key
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
// BlockedUser Navigation Property
public virtual ICollection<BlockedUser> BlockedUsers { get; set; }
}

Foreign Key Relationship EF Code First

I'm busy creating my first EF code first model and I've come across a slightly confusing problem.
I have a number of model classes that each inherit from a base model class that has three common properties I want used in all model classes. These properties are Id, LastUpdated and LastUpdatedBy.
Id is the primary key of each model class.
LastUpdated is a foreign key to my 'User' model class.
LastUpdatedBy is a datetime field that indicates the last time the record was modified.
So what I'd like to setup is the 1 to 1 foreign key relationship from my base class to my 'User' model class but I'm receiving the exception:
Multiplicity is not valid in Role 'Profile_LastUpdatedByUser_Source'
in relationship 'Profile_LastUpdatedByUser'. Because the Dependent
Role properties are not the key properties, the upper bound of the
multiplicity of the Dependent Role must be '*'
This is my ModelBase class:
public class ModelBase
{
public int Id { get; set; }
public DateTime LastUpdated { get; set; }
[ForeignKey("LastUpdatedByUser")]
[Required]
public int LastUpdatedByUserId { get; set; }
public virtual User LastUpdatedByUser { get; set; }
}
This is one of my model classes:
public class Profile : ModelBase
{
[StringLength(25, MinimumLength=1)]
[Required(ErrorMessage="First Name is Required")]
public string FirstName { get; set; }
[StringLength(25, MinimumLength = 1)]
[Required(ErrorMessage = "Last Name is Required")]
public string LastName { get; set; }
[StringLength(25, MinimumLength = 1)]
[Required(ErrorMessage = "Email Address is Required")]
public string Email { get; set; }
public string Mobile { get; set; }
public string HomePhone { get; set; }
public string WorkPhone { get; set; }
public string ImageSource { get; set; }
public Squable.Model.Enums.MembershipType.MembershipTypeEnum MembershipType { get; set; }
}
This is my user class (Please ignore the Password property, I'll fix that later ;) ):
public class User : ModelBase
{
public string UserName { get; set; }
public string Password { get; set; }
public int ProfileId { get; set; }
public virtual Profile Profile { get; set; }
}
I don't know if what I am doing is best practise but I could do with some advice as to how to either fix the problem or maybe just some pointers in the right direction.
Move
public int Id { get; set; }
to User class and to Profile you can also change the names to UserId and to ProfileId and move
public virtual User LastUpdatedByUser { get; set; }
to Profile class.
I have a bad experience with sharing Id in base entity If you are planning to use Repository and UnitOfWork pattern you will get a lot of problems later. Check your current database structure and tables with SQL Server Management Studio.
More Info TPH

Categories

Resources