ASP.NET Core Conflict with Foreign Key - asp.net

I have got several models:
Course.cs
public class Course
{
public Guid Id { get; set; }
public ICollection<ApplicationUser> Teacher { get; set; }
public string Name { get; set; }
public string ShortName { get; set; }
public DateTime CreationDate { get; set; }
public bool IsActive { get; set; }
}
Group.cs
public class Group
{
public Guid Id { get; set; }
public ApplicationUser Mentor { get; set;}
public string DisplayName { get; set; }
public string GroupName { get; set; }
public DateTime StartYear { get; set; }
public string InviteCode { get; set; }
public ICollection<ApplicationUser> Students { get; set; }
public ICollection<Course> Courses { get; set; }
}
ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
[Required]
public string Firstname { get; set; }
[Required]
public string Surname { get; set; }
public bool Gender { get; set; }
public DateTime Birthdate { get; set; }
//[Required]
public string InviteCode { get; set; }
public Guid GroupId { get; set; }
[ForeignKey("GroupId")]
public Group CurrentGroup { get; set; }
public ICollection<Group> PastGroups { get; set; }
}
Now when I try to register (using Identity) a user (not even trying to give the user a group) I receive this error:
SqlException: The INSERT statement conflicted with the FOREIGN KEY
constraint "FK_AspNetUsers_Groups_GroupId". The conflict occurred in
database "aspnet-Project_Dojo-3af15f80-8c62-40a6-9850-ee7a296d0726",
table "dbo.Groups", column 'Id'. The statement has been terminated.
In my modelBuilder I have added some logics for the relations between Group, ApplicationUser (Students) and the Foreign Key:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);\\
builder.Entity<ApplicationUser>()
.HasOne(p => p.CurrentGroup)
.WithMany(b => b.Students)
.HasForeignKey(p => p.GroupId);
}
I don't know what this is exactly doing, but I've been browsing some Stackoverflow threads to come to this code (migrations weren't working without it).
I look forward to a solution for my problem. Once again, I'm not doing ANYTHING with the groups yet when registering.
Thanks in advance!

not even trying to give the user a group
Well there's your problem, it's required.
Either provide a group, or make it optional by making the foreign key nullable (Guid? GroupId).
Because it's currently a non-nullable struct, it'll have a default value of all zeroes (Guid.Empty). This FK is not known in your database, resulting in the error you see.

Related

Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths even after removing the affected field completely

I'm quite new to .net and entity framework (this is my first project) and I'm getting the following error when trying to update the database:
*Introducing FOREIGN KEY constraint 'FK_Rating_User_UserId' on table 'Rating' 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 or index. See previous errors.*
I tried doing what it says (at least I think so) by adding the following to my dbContext class:
protected override void OnModelCreating(ModelBuilder modelbuilder)
{
modelbuilder.Entity<Rating>().HasOne(u => u.User).WithMany().OnDelete(DeleteBehavior.Restrict);
modelbuilder.Entity<Rating>().HasOne(g => g.Game).WithMany().OnDelete(DeleteBehavior.Restrict);
}
Not sure have I formulated that method correctly but it did not help (I tried with different DeleteBehavior like SetNull and NoAction)
The thing that really got me confused is that the issue appears even after removing all fields related to other tables from Rating class or even all references between all classes.
My Rating class:
public class Rating
{
public long RatingId { get; set; }
//[Rating]
public virtual Game Game { get; set; } // issue appears even after removing this and User line
//[Rating]
public int Score { get; set; }
public string CommentTitle { get; set; }
public string CommentDescription { get; set; }
//[Rating]
public virtual User User { get; set; }// issue appears even after removing this and Game line
}
User class:
public class User
{
public long UserId { get; set; }
//[Required]
public bool IsModerator { get; set; }
//[Required]
public string Username { get; set; }
//[Required]
public string Email { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
//[Required]
public string Password { get; set; }
//[Required]
public string Salt { get; set; }
public string Description { get; set; }
}
Game class:
public class Game
{
public long GameId { get; set; }
//[Required]
public virtual User User { get; set; }
//[Required]
public string Title { get; set; }
public string Description { get; set; }
//[Required]
public string PricingType { get; set; }
public float MinDonation { get; set; }
public float MaxDonation { get; set; }
//[Required]
public string FileLocation { get; set; }
public float AverageRaiting { get; set; }
public int DownloadCount { get; set; }
}
GameImage class (probably unrelated to the issue just wanted to give a full context)
public class GameImage
{
public long GameImageId { get; set; }
//[Required]
public virtual Game Game { get; set; }
//[Required]
public string Location { get; set; }
//[Required]
public bool IsThumbnail { get; set; }
}
dbContext class:
public class dbContext : DbContext
{
public dbContext(DbContextOptions<dbContext> options) : base(options)
{
}
public DbSet<User> User { get; set; }
public DbSet<Rating> Rating { get; set; }
public DbSet<GameImage> GameImage { get; set; }
public DbSet<Game> Game { get; set; }
}
The issue only appeared after I tried to update the database. The first few migrations and updates were ok, however, then I tried adding [Required] annotation (you can see them commented in the above code) as I noticed that most of the fields were created as nullable in my database - after that the issue starting to occur even after removing the annotations.
In case that matters, I'm using Visual Studio 2019 and SQL Server Express
Does anyone have any idea what may be the cause of this?
Edit:
Image of of my database schema diagram from SSMS
As you can see in the database schema it's visible that there are indeed cycles in the database, however, I cannot get rid of them as Entity Framework's command "Update-Database" does not update the DB and just throws the error mentioned above.
Based on my test, you can try the following steps to solve the problem.
First, please change your dbcontext class into the following code.
public class dbContext : DbContext
{
public dbContext() : base("name=MyContext") { }
public DbSet<User> User { get; set; }
public DbSet<Rating> Rating { get; set; }
public DbSet<GameImage> GameImage { get; set; }
public DbSet<Game> Game { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
Second, please delete all the tables the database.
Third, please try the following command in your package console.
PM> Update-Database -Force
Finally, you can see the new tables in the databse.

Configure a principal key or a set of compatible foreign key properties for this relationship error with EF core

I am not sure why I am getting this error:
System.InvalidOperationException: 'The relationship from 'Insured' to 'Quote.Insureds' with foreign key properties {'InsuredID' : string} cannot target the primary key {'InsuredID' : string, 'ProducerID' : string} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship.'
I am trying to configure two keys in the Quote model, one for my Insured model and one for my Producer. I attempted to only have one key before and just use foreign keys but that didnt work.
public class Producer
{
[Key]
public string ProducerID { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
public class Insured
{
[Key]
public string InsuredID { get; set; }
public string NamedInsured { get; set; }
public string Address1 {get; set;}
public class Quote
{
public string InsuredID { get; set; }
public string ProducerID { get; set; }
[ForeignKey("ProducerID")]
public IList<Producer> Producers { get; set; }
[ForeignKey("InsuredID")]
public IList<Insured> Insureds { get; set; }
In my DB context:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Quote>().HasKey(q => new { q.InsuredID , q.ProducerID});
It is not possible to reference an array with a key
It needs to be an object rather than a collection.
public class Quote
{
public string InsuredID { get; set; }
public string ProducerID { get; set; }
[ForeignKey("ProducerID")]
public Producer Producer { get; set; }
[ForeignKey("InsuredID")]
public Insured Insured { get; set; }
}

Unable to add second self Referencing FK to model, causes Unable to determine the principal end error

First off, I know there are a lot of posts about the Unable to determine the principal end of an association between the types error but ever single one I see does not match my issue, if I missed one sorry about that.
I have built an Entity that will end up referencing it's self twice and when I put the code in for the first self reference it works fine, as soon as ad the code for the second it breaks. Doing some testing I have found that if I use either of the self references by them self everything works fine, it is only when I add the second self reference that it breaks. The code I am using for the self references is:
[ForeignKey("ManagerID")]
public User Manager { get; set; }
//Auditing Fields
public DateTime DateCreated { get; set; }
public int? UpdatedByUserID { get; set; }
public DateTime? DateUpdated { get; set; }
public DateTime LastAutoUpdate { get; set; }
[ForeignKey("UpdatedByUserID")]
public User UpdatedByUser { get; set; }
The full entity code block is:
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public int ADPFileNumber { get; set; }
[Required]
public string ADUserName { get; set; }
public int AirCardCheckInLateCount { get; set; }
[Required]
public string Email { get; set; }
public DateTime? EndDate { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public int ManagerID { get; set; }
public string MobilePhone { get; set; }
[Required]
public string Office { get; set; }
[Required]
public string Phone { get; set; }
public decimal PTO { get; set; }
public DateTime StartDate { get; set; }
public int VehicleCheckInLateCount { get; set; }
public int WexCardDriverID { get; set; }
[ForeignKey("ManagerID")]
public User Manager { get; set; }
//Auditing Fields
public DateTime DateCreated { get; set; }
public int? UpdatedByUserID { get; set; }
public DateTime? DateUpdated { get; set; }
public DateTime LastAutoUpdate { get; set; }
[ForeignKey("UpdatedByUserID")]
public User UpdatedByUser { get; set; }
}
What am I missing that cause the second self reference to break?
You have to indicate the principal end of both associations explicitly. You can do that with the class you had originally, without inverse collection properties:
modelBuilder.Entity<User>()
.HasOptional(u => u.Manager)
.WithMany()
.HasForeignKey(u => u.ManagerID);
modelBuilder.Entity<User>()
.HasOptional(u => u.UpdatedByUser)
.WithMany()
.HasForeignKey(u => u.UpdatedByUserID);
Note that ManagerID should be an int? as well. You can't create any User if it requires another user to preexist. That's a chicken-and-egg problem.
As mentionned in Multiple self-referencing relationships in Entity Framework, you seem to be missing the other part of the relationship.
i.e.
[InverseProperty("Manager")]
public virtual ICollection<User> ManagedUsers {get;set;}
[InverseProperty("UpdatedByUser")]
public virtual ICollection<User> UpdatedUsers {get;set;}
EDIT: based on #Gert Arnold's answer you should indeed add the [InverseProperty] attribute

Foreign key relationship

I'm trying to setup a foreign key using the following two classes.
I want to use pAcqType as an enum and store the names of the types in another table. How should I setup my classes to do this?
public class Property
{
[Key]
public int pID { get; set; }
public string pAddress { get; set; }
public string pCounty { get; set; }
public string pCity { get; set; }
public string pState { get; set; }
public string pzip { get; set; }
public virtual PropertyAcquisitionType pAcqType { get; set; } <-- foreign key
}
public class PropertyAcquisitionType
{
[Key]
public int patID { get; set; }
public string patName { get; set; }
}
UPDATE
Dan got me thinking. And I tried the following and it seems to have worked out.
It setup the foreign key on the table like I wanted. And it didn't even ask for an inverse on the other table.
public int? pAcqType { get; set; }
[ForeignKey("pAcqType")]
public PropertyAcquisitionType patID { get; set; }
Is the foreign key required (NOT NULL in the database)?
public int pAcqTypeId { get; set; }
[ForeignKey("pAcqTypeId")]
public virtual PropertyAcquisitionType pAcqType { get; set; }
Otherwise,
public int? pAcqTypeId { get; set; }
[ForeignKey("pAcqTypeId")]
public virtual PropertyAcquisitionType pAcqType { get; set; }
Then in your other class, add an inverse relationship:
public class PropertyAcquisitionType
{
[Key]
public int patID { get; set; }
public string patName { get; set; }
[InverseProperty("pAcqType")]
public virtual ICollection<Property> pOfThisType { get; set; }
}
Here is one way you could define the relationship using the fluent API (without attributes in the entity classes). Note with this method, you should not need to add a properties property on the PropertyAcquisitionType entity to satisfy the inverse side of the relationship, because the .WithMany() tells EF what it needs to know:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Property>()
.HasKey(x => x.pID)
.HasRequired(x => x.pAcqType) // or HasOptional if using int?
.WithMany() // or WithMany(x => x.pOfThisType) if you want to add / keep the inverse property
.HasForeignKey(x => x.pAcqTypeId)
;
}
}

Code first one to one foreign key

I have two model class, where I want to make one-to-one relation. When I make migration, I get an error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint
"FK_dbo.Uzytkownik_dbo.UserProfile_UserId". The conflict occurred in
database "db_wydarzenia", table "dbo.UserProfile", column 'UserId'.
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
[Table("Uzytkownik")]
public class Uzytkownik
{
[Key]
public int UzytkownikID { get; set; }
public int UserId { get; set; }
public string Imie { get; set; }
public string Nazwisko { get; set; }
public string Telefon { get; set; }
public string Email { get; set; }
[ForeignKey("UserId")]
public UserProfile UserProfile { get; set; }
}
EDIT:
Problem solved :)
I remove all data from uzytkownik table and it's go.
If you want one-to-one - you cannot have both the primary-key and the foreign-key specified. One-to-one is modeled via primary-keys (pk == pk), otherwise it becomes 'multiplicity' (and just typical one-to-many).
To get what you want just remove your other PK - and user UserId as both primary and fk...
[Table("Uzytkownik")]
public class Uzytkownik
{
// [Key] public int UzytkownikID { get; set; }
[Key]
public int UserId { get; set; }
[ForeignKey("UserId")]
public UserProfile UserProfile { get; set; }
}

Resources