Foreign key collection is null - c#

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

Related

EF Core 2.2.6: Unable to map 2 foreign keys to the same table

I am having issues trying to map two fields that are foreign keys into the same table. The use case is for a modifier and creator. My class already has the Ids, and then I wanted to add the full User object as virtual.
I am using a base class so that each of my tables have the same audit fields:
public class Entity
{
public long? ModifiedById { get; set; }
public long CreatedById { get; set; } = 1;
[ForeignKey("CreatedById")]
public virtual User CreatedByUser { get; set; }
[ForeignKey("ModifiedById")]
public virtual User ModifiedByUser { get; set; }
}
The child class is very simple:
public class CircleUserSubscription : Entity
{
[Required]
public long Id { get; set; }
public long SponsorUserId { get; set; }
[ForeignKey("SponsorUserId")]
public virtual User User { get; set; }
public long TestId { get; set; }
[ForeignKey("TestId")]
public virtual User Test { get; set; }
}
This is a standard junction table.
When I try to generate the migration, I am getting errors that I don't understand fully.
Unable to determine the relationship represented by navigation property 'CircleUserSubscription.User' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I tried what this answer had, but the code is basically the same: https://entityframeworkcore.com/knowledge-base/54418186/ef-core-2-2---two-foreign-keys-to-same-table
An inverse property doesn't make sense since every table will have a reference to the user table.
For reference, here is the User entity:
public class User : Entity
{
public long Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I am hoping you all can help me out, TIA :)
EDIT: One thing to note, all of this worked fine when the entity class was as follows:
public class Entity
{
public long? ModifiedById { get; set; }
public long CreatedById { get; set; } = 1;
}
It was only after I added the entity that things went awry.

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; }
}

EF code first Reference key as primary key

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; }

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