This is my first time working with database so I'm still trying to understand how all this works.
I'm trying to write my data (User, Note, Group) to database. I have three classes.
First one is User:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public List<Group> groups { get; set; }
public User()
{
this.groups = new List<Group>();
}
}
Note:
public class Note
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public string Content{ get; set; }
public string Password { get; set; }
public List<Group> groups { get; set; }
}
And Group:
public class Group
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
}
I know I should add foreign key but I don't know where and how. I'm really stuck so any help would be greatly appreciated!
Before you add foreign key. First you must define the relationship cardinality between each tables. To define it, you can just imagine how each table are represented in real life.
For example, a group can/must contain more than one user. And a user can be inside a single group or more at once.
So we define the relationship between a group and a user as MANY TO MANY, unless, you define it so that one user may only be registered to one group. In which case the relationship would become ONE TO MANY. With ONE being the group table and MANY refers to the user table.
Now, once the relationship is defined, usually the foreign key is set in the MANY table, in this case, it's the user table. So every user would have a foreign key called "Group".
As for the MANY TO MANY relationship the foreign key is set in both table. So that each table contains the key of the other.
Related
This is my code:
namespace MyProject.Models.Database
{
public class Recipe
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
public string? Description { get; set; }
public string? Picture { get; set; }
public int Worktime { get; set; }
public int? Cooktime { get; set; }
public int Difficulty { get; set; }
public int Portions { get; set; }
public List<Ingredient> Ingredients { get; set; }
}
public class Ingredient
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid IngredientId { get; set; }
public int Qty { get; set; }
public string QtyUnit { get; set; }
}
}
I want the class "Recipe" to include many elements of type "Ingredient". Ive read stuff about One-to-One and Many-To-Many but i just dont get it...
any Ideas?
thx
One recipe can consist of many ingredients, one ingredient can also be in many recipes. This is a many-to-many relationship.
What you need to do is create a new class that contains Id, RecipeId, IngredientId.Name that class something like RecipeIngredient. When you are creating a DbSet<RecipeIngredient> in your db context, name your table RecipesIngredients.
What should be the data types of the properties in RecipeIngredient?
The Id property will be the primary key, you can decide the data type.
RecipeId will be a foreign key for the Recipe, so it needs the same data type as the primary key of the Recipe (in your case Guid).
IngredientId will be the foreign key for the Ingredient, so the data type will again be Guid in your case.
Note that instead of putting Id in your RecipeIngredient, you can create a composite key instead.
When should you do that? -> here
I suggest you learn about the different relationships and how to apply them using C# and Entity Framework Core -> here
Good luck on your learning journey! When you don't feel you understand a topic, don't worry and don't get discouraged, you just need more experience. Keep up the good work :)
I'm pretty new to Entity Framework as a FE Dev doing hobby stuff in my spare time. I'm trying to setup a many to many relationship with the following two classes. I want to have a table with all the users of the application. Each user can have multiple DuBists. In each DuBist there can participate multiple Users but only one User can be the active User. So I try like this (and many other things but that seams most logical to me):
public class DuBist : EntityData
{
public string Title { get; set; }
public virtual User ActiveUser { get; set; }
public int ChangeCount { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User : EntityData
{
public string UserId { get; set; }
public string Name { get; set; }
public string ImageRef { get; set; }
[JsonIgnore]
public virtual ICollection<DuBist> DuBists { get; set; }
}
When I add a new DuBist I get this exception:
SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.Users'. Cannot insert duplicate key in object 'dbo.Users'. The duplicate key value is (0).
Mock Data, so one of the users has the id "0".
Looks like I don't know enough to google what is wrong here, any help is appreciated a lot =)
I have a simple User Class
public class User
{
public int ID { get; set; }
[Required]
public virtual ApplicationUser LoginID { get; set; }
[Required]
public string Name { get; set; }
public string JobTitle { get; set; }
[DefaultValue(UserRole.Standard)]
public UserRole Role { get; set; }
public virtual Company Company { get; set; }
public string Email { get { return LoginID.Email; } }
public bool HasAccess(UserRole TargetRole)
{
//Non-relevant logic
}
}
And I also have a Company class defined as
public class Company
{
public int ID { get; set; }
[Required]
[MaxLength(length: 70)]
public string Name { get; set; }
public virtual ICollection<User> Employees { get; set; }
public virtual ICollection<CompanyEmailDomain> Domains { get; set; }
public ICollection<User> Managers { get { return Employees.Where(x => x.Role == UserRole.Manager).ToList(); } }
}
However, when I run the add-migration command, it tries to add 3 Foreign keys on the User table to the Company table. Can anyone tell me why this would be the case?
AddColumn("dbo.Users", "Company_ID", c => c.Int());
AddColumn("dbo.Users", "Company_ID1", c => c.Int());
AddColumn("dbo.Users", "Company_ID2", c => c.Int());
Entity Framework simply counts the associations between User and Company. It detects three of them:
Company in User.
Employees in Company
Managers in Company
They're all 1-n (Company - User), so, EF concludes, User needs three foreign keys.
You know that Managers is a computed property. In fact, the property shouldn't even be be mapped. You should add the [NotMapped] attribute to it or map it as ignored by the fluent mapping API.
Also, you know that User.Company and Company.Employees are two ends of one association. But because of the two ICollection<User> properties, EF doesn't know which one to choose for the other end (the inverse end) of User.Company.
Now if you unmap Company.Managers, EF will see two properties --User.Company and Company.Employees-- and assume they belong together. So by unmapping one property, only one foreign key will be created.
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.
These are my model classes:
public class Organization
{
public Organization()
{
}
[DisplayName("Organization Id")]
public int OrganizationId { get; set; }
[StringLength(128)]
[DisplayName("Organization Name")]
public string Name { get; set; }
}
public class User
{
public User()
{
Roles = new List<Role>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid UserGuid { get; set; }
[StringLength(25)]
public string FirstName { get; set; }
[StringLength(25)]
public string LastName { get; set; }
public virtual List<Role> Roles { get; set; }
public int OrganizationId { get; set; }
[ForeignKey("OrganizationId")]
public virtual Organization Organization { get; set; }
}
This is my code:
Organization organization = new Organization { Name = "Test", };
context.Organizations.Add(organization);
And I get this:
The INSERT statement conflicted with the FOREIGN KEY constraint
\"Organization_Users\". The conflict occurred in database
\"SampleDB\", table \"dbo.Organizations\", column
'OrganizationId'.\r\nThe statement has been terminated.
Isn't this weird? I am just adding an organization. What problem can it possibly have in this?
P.S: My user table does have OrganizationId that is foreign key and pointing to Organization table. So far so good but why is the exception thrown? I am adding a master Organization record. How does that violate foreign key constraint?
I would expect the database id to be generated for the organisation as well:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DisplayName("Organization Id")]
public int OrganizationId { get; set; }
Either that, or you need toset it to a valid, unique value yourself before saving
Alternative guess:
The name Organization_Users suggests that there is (or was) a relation from the Organization table to th Users (perhaps via a relation table). Did you show the full code? Code there be remnants of this old relationship in the database? It is not enough to remove such relations just from the C# code (because the datatabase will continue checking the constraints, until the unused fields/relations are dropped from the actual database schema).
It appears that EF has created the relationship in the wrong direction.
The User class should have an Organization not an OrganizationID.
The Organization class should have a list of users.