EF code first Reference key as primary key - c#

Landed up in a quite ridiculous situation here.
I'm coding in EF core, ASP.NET core, Visual Studio 2017 community.
I have a model which does not have a primary key like:
public class LoginRecord
{
public User User { get; set; }
public int UserId { get; set; }
public DateTime LastLogin { get; set; }
public int LoginCount { get; set; }
}
where User is a table with all the fields like name, email etc.
When I do add-migration, an error pops up saying:
The entity type 'LoginRecord' requires a primary key to be defined.
Then I tried by adding the [Key] annotation to the UserId field like this:
public class LoginRecord
{
public User User { get; set; }
[Key]
public int UserId { get; set; }
public DateTime LastLogin { get; set; }
public int LoginCount { get; set; }
}
but now, EF creates a new column called UserId1 which becomes the foreign key.
I need the UserId to be just a reference key and don't need a primary key for this table.
Is it possible? If yes please help!

You should add an primary key.
I've learned that every table should get a field which is named like the table + id. You could also name it id if you like it more. :)
So that every record gets unique.
So I would advice you to change your model to something like this:
public class LoginRecord
{
[Key]
public int LoginRecordID {get; set;}
public User User { get; set; }
public int UserId { get; set; }
public DateTime LastLogin { get; set; }
public int LoginCount { get; set; }
}

Try:
[ForeignKey("UserId"), Column(Order = 0)]
public int UserId { get; set; }

Related

EF Optional Relationships / Nullable / Navigation Table

I solved this, answer below.
I am new to EF and having a lot of difficulty trying to get an optional relationship. I am looking to have a relationship where I have ApiLogItem Model with an UserId property which can be null / anonymous user or a logged in user to track all Api calls. The goal is to have Existing Users who do some create a new object to be linked to that object. I do not want to create new Users every time a new ApiLogItem is created.
I have tried a dozen variations with virtual / foreign key attributes and I am stumped. It works great for null / anonymous user but once I attach an actual user to the ApiLogItem it will not insert. I get this error:
{"Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert
duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is
(09c0d2e2-b003-4be8-a62a-08d7268af58e).\r\nThe statement has been
terminated."}
I have tried following this tutorial but alas no luck.
https://www.learnentityframeworkcore.com/conventions/one-to-many-relationship#targetText=EF%20Core%20will%20create%20a,public%20class%20Author
public class ApiLogItem
{
[Key]
public long Id { get; set; }
[Required]
public int StatusCode { get; set; }
[Required]
public string Method { get; set; }
[MaxLength(45)]
public string IPAddress { get; set; }
public Guid? UserId { get; set; }
public ApplicationUser User { get; set; }
}
public class ApplicationUser : IdentityUser<Guid>
{
[MaxLength(64)]
public string FirstName { get; set; }
[MaxLength(64)]
public string LastName { get; set; }
public List<ApiLogItem> ApiLogItems { get; set; }
}
Error happens when I want to create a new ApiLogItem:
using (ApplicationDbContext _dbContext = new ApplicationDbContext(_optionsBuilder.Options))
{
_dbContext.ApiLogs.Add(apiLogItem);
await _dbContext.SaveChangesAsync();
}
I have reviewed several other stackoverflow issues and none seem to fix. You can find the repository here:
https://github.com/enkodellc/blazorboilerplate
You are calling applicationDbContextSeed.SeedDb(); in your Startup class each time you run, and in your SeedDb method, you are adding a user with a static id 09C0D2E2-B003-4BE8-A62A-08D7268AF58E.
The first time you run, it will create that user; the second time, it will fail because that user (with that id) already exists.
I figured it out. It needs a virtual in the parent and just the id in the child. I need to learn more about EF as it is not intuitive to me. Will post a better answer later today after testing.
public class ApplicationUser : IdentityUser<Guid>
{
[MaxLength(64)]
public string FirstName { get; set; }
[MaxLength(64)]
public string LastName { get; set; }
public ICollection<ApiLogItem> ApiLogItems { get; set; }
}
public class ApiLogItem
{
[Key]
public long Id { get; set; }
[Required]
public int StatusCode { get; set; }
[Required]
public string Method { get; set; }
[MaxLength(45)]
public string IPAddress { get; set; }
public Guid? UserId { get; set; }
}

Foreign key collection is null

So, I was trying to get something with EF core. I'm doing code-first as it's best for me (I prefer it also cause no database has to be provided for users). Anyways, I'm going to have a big database with loads of relations, so I have to use foreign keys.
However, the foreign key collection is always null, even if in the database it's linked. I got these 2 models:
User:
[Table("users")]
public class User
{
[Key]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("name")]
[StringLength(15, MinimumLength =2)]
[Required]
public string Name { get; set; }
[Column("password")]
[StringLength(100)]
[Required]
public string Password { get; set; }
[Column("email")]
[StringLength(30, MinimumLength =6)]
[Required]
public string Email { get; set; }
public List<UserActivityPoints> Activitypoints { get; set; }
}
UserActivityPoints:
[Table("activitypoints")]
public class UserActivityPoints
{
[Key]
[Column("type")]
public int Type { get; set; }
[Column("amount")]
public int Amount { get; set; }
[Key]
[Column("user_id")]
public User User { get; set; }
}
So, one thing that already was weird is, in the database, the user_id column becomes UserId, however it is correctly linked to the users, as shown below:
A picture of PHPMyAdmin showing it's linked correctly
In my database context, I have the following code:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().ToTable("User");
modelBuilder.Entity<UserActivityPoints>().ToTable("activitypoints");
}
I run the following code:
var i = ProductionDbContext.GetInstance().Users.Find(1).Activitypoints;
I got a record shown in the following picture:
The record is added in the database
However, when I debug, i is always null, even though user 1 has a record in the activity points table. Am I doing something wrong or am I forgetting something?
In UserActivityPoints you have [Key] above both Type and UserId - EFCore thinks you are trying to make the two combined into your primary key. Your UserActivityPoints should look like:
[Table("activitypoints")]
public class UserActivityPoints
{
[Key]
[Column("type")]
public int Type { get; set; }
[Column("amount")]
public int Amount { get; set; }
[Key]
[Column("user_id")]
public int UserId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
}
I've removed the key, given you a column just for ID, and an object for User. Now it should work properly. Doc: https://learn.microsoft.com/en-us/ef/core/modeling/keys

How can I insert Billing Information after Providing Patient Diagnosis Information in one-to-one relationship One after another

The Application I am trying to make is Hospital Management System. In the EnterPatientDiagnosis Form(screenshot is given at the end), I need to Add The Patient's Diagnosis Information 1st then I need to Add its associated Billing Information. Here,Both of tables Primary Key Column is an Identity Column.
This is a common step in many Systems .But I still couldn't find details on how to achieve it.
One solution I thought of is to insert all the Diagnosis Information keeping the FK_billId attribute Null using Stored Procedure and get the DiagnosisId as output parameter form the Stored Procedure. Then when user will Submit Bill information I will use the BillId and DiagnosisId to update the previously inserted row in the Diagnosis Table. But I do not like this approach for 2 reason:
Firstly, Because it has an extra update query. Since, If I used the DiagnosisId as a foreign key between this 2 Database Tables rather than BillId then there would not be any need for this update query. But I haven't found anywhere giving any rules/precedence on which Key you should use as FK in One-to-One relation.
Secondly, It conflicts with the Entity Class that I have created. I have manually created 2 classes for this 2 tables in my Entity Layer. So, If I want to insert row through entity layer then I would have to give The Billing class a new Property named DiagnosisId which is contradictory with my Database Table Schema.
Here is the 2 classes in Entity Layer:
public class EntityPatientDiagnosis
{
//Diagnosis Id is automatically assigned
public int DiagnosisId { get; set; }
public int PatientId { get; set; }
public string Symptoms { get; set; }
public string DiagnosisProvided { get; set;}
public string AdministeredBy { get; set; }
public DateTime DateofDiagnosis { get; set; }
public string FollowUpRequired { get; set; }
public DateTime DateOfFollowUp { get; set; }
public int BillId { get; set; } //BillId -> Foreign Key
}
public class EntityBilling
{
//BillId -> Primary Key ->set automatically
public int BillId { get; set; }
public int BillAmount { get; set; }
public string CardNumber { get; set; }
public string ModeOfPayment { get; set; }
}
Here is the picture of the ERD of the tables and Web Forms:
You can try a different approach. You can change the relationship between entities PatientDiagnosis and Billing. So, at first you can create a PatientDiagnosis entry and then create a Billing entry for it.
public class EntityPatientDiagnosis
{
//Diagnosis Id is automatically assigned
public int DiagnosisId { get; set; }
public int PatientId { get; set; }
public string Symptoms { get; set; }
public string DiagnosisProvided { get; set;}
public string AdministeredBy { get; set; }
public DateTime DateofDiagnosis { get; set; }
public string FollowUpRequired { get; set; }
public DateTime DateOfFollowUp { get; set; }
}
public class EntityBilling
{
//BillId -> Primary Key ->set automatically
public int BillId { get; set; }
//DiagnosisId -> Foreign Key unique
public int DiagnosisId { get; set; }
public int BillAmount { get; set; }
public string CardNumber { get; set; }
public string ModeOfPayment { get; set; }
}

Code First Optional One-To-One Relationship

Writing a model for situation where I have two tables which are customers and users. Each user record might have an optional related customer record and vice versa, but none of them is a must. I figured out that FK Associations are not what I need, but Independent Associations are. But I just can find a way to make it work, I keep getting the 'Unable to determine the principal end...The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.' exception.
My models are very simple:
public class User
{
[Key]
public int Id { get; set; }
[StringLength(20)]
public string CustomerId { get; set; }
public string Password { get; set; }
public bool Locked { get; set; }
//[ForeignKey("CustomerId")]
public virtual Customer Customer { get; set; }
}
public class Customer
{
[Key]
[Column("Id", TypeName = "nvarchar")]
[StringLength(20)]
public string Id { get; set; } // nvarchar 20
[Required]
public string GivenName { get; set; } // nvarchar 100
[Required]
public string Surname { get; set; } // nvarchar 100
//[InverseProperty("Customer")]
public virtual User User { get; set; }
}
I've tried to add the ForeignKeyAttribute and InversePropertyAttribute, which are currently commented out, but they didn't help either. I would prefer to use data annotations and not fluent API, if it's possible in my case.
In one-to-one relation one end must be principal and second end must be dependent. Principal end is the one which will be inserted first and which can exist without the dependent one. Dependent end is the one which must be inserted after the principal because it has foreign key to the principal. When configuring one-to-one relationships, Entity Framework requires that the primary key of the dependent also be the foreign key.This problem is most easily solved by using a ForeignKey annotation on the dependent class to identify that it contains the foreign key. In your case, Customer could be the dependent and its key, Customer.UserId, should also be the foreign key. But both Keys must be declared using the same type:
public class User
{
[Key]
public int Id { get; set; }
public virtual Customer Customer { get; set; }
}
public class Customer
{
[Key, ForeignKey("User")]
public int UserId { get; set; }
public virtual User User{ get; set; }
}
I don't know how to resolve your problem using Data Annotations, but if you want to use Fluent Api, I think the configuration of the relationship would be like this:
modelBuilder.Entity<User>().HasOptional(u => u.Customer).WithOptionalPrincipal(c => c.User);
Update
I understand your escenario, but if you have the same columns that you show in your model, I think you should have a one-to-many relationship mapped in DB instead one-to-one. Try to map your relationship this way:
public class User
{
[Key]
public int Id { get; set; }
public string Password { get; set; }
public bool Locked { get; set; }
public string CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customer Customer { get; set; }
}
public class Customer
{
[Key]
[Column("Id", TypeName = "nvarchar")]
[StringLength(20)]
public string Id { get; set; } // nvarchar 20
[Required]
public string GivenName { get; set; } // nvarchar 100
[Required]
public string Surname { get; set; } // nvarchar 100
public virtual ICollection<User> Users { get; set; }
}
Remember map your properties with the same column'names that you have in DB.

How to get Entity Framework Code First and nullable foreign key properties to work?

I'm trying to create a simple entity framework code first application. I have these classes:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public virtual ActivationTicket ActivationTicket { get; set; }
}
public class ActivationTicket
{
public int ActivationTicketId { get; set; }
public virtual User User { get; set; }
public string Ticket { get; set; }
}
When I try to create a new user and save it to the database (a user without a ActivationTicket that is) I receive an exception
The INSERT statement conflicted with the FOREIGN KEY constraint "ActivationTicket_User". The conflict occurred in database "Test", table "dbo.ActivatioTickets", column 'ActivationTicketId'. The statement has been terminated.
I assume EF treats the mapping between User and ActivationTicket as 1-1 but it should be 1-0..1
What do I have to do to get this to work?
You will need a mapping rule like this:
modelBuilder
.Entity<User>()
.HasOptional<ActivationTicket>(u => u.ActivationTicket)
.WithOptionalPrincipal();
This will give you an ActivationTickets table with a UserId that is nullable.
#b3n
It should be enough to do this, at least with VS 2013:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public int? ActivationTicketId { get; set;}
public virtual ActivationTicket ActivationTicket { get; set; }
}
This is the important part:
public int? ActivationTicketId { get; set;}
This will specify the foreignkey in your "User" table for the ActivasionTicket and define that it's optional.
credits go to:
http://forums.asp.net/t/1948351.aspx?Change+Foreign+Key+to+nullable+using+Code+First#5554732
I had the same problem and it instantly worked for me.
Also as a note i marked all my primary keys with the data annotation "[Key]". This might be necessary in order to make this work.

Categories