In my HomeController, I am having trouble with my create function accessing the database. After submitting the form in my browser, this is the error that shows:
Error Given
MySqlException: Cannot add or update a child row: a foreign key constraint fails (petshelterdb.pets, CONSTRAINT FK_Pets_Owners_OwnerId FOREIGN KEY (OwnerId) REFERENCES owners (OwnerId) ON DELETE CASCADE)
MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in ResultSet.cs, line 49
I am not using a login/registration. The idea is that I have a "bulletin board" that shows pets that can be adopted and owners that can adopt. A new pet or owner can be added to the board. If I select the owner's name, I can have that owner "adopt" a pet on the board. I designated in the HomeController code which line is the issue.
Since I'm not working with a UserId, I'm not sure how to go about this.
Pet.cs
namespace petShelter.Models
{
public class Pet
{
[Key]
public int PetId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Type { get; set; }
[Required]
public string Description { get; set; }
public string Skill1 { get; set; }
public string Skill2 { get; set; }
public string Skill3 { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public Owner Owner { get; set; }
public int OwnerId { get; set; }
}
}
Owner.cs
namespace petShelter.Models
{
public class Owner
{
[Key]
public int OwnerId { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
List<Pet> MyPets { get; set; }
public string FullName()
{
return FirstName + " " + LastName;
}
}
}
HomeController.cs
[HttpPost("/pet/new")]
public IActionResult Create(Pet newPet)
{
if (ModelState.IsValid)
{
_context.Add(newPet);
_context.SaveChanges(); ***THIS IS WHERE ISSUE OCCURS***
return RedirectToAction("Index", new { id = newPet.PetId });
}
else
{
if (newPet.Name == null)
{
ModelState.TryAddModelError("Name", "The Name field is required");
}
return View("NewPet", newPet);
}
}
PetShelterContext.cs
namespace petShelter.Models
{
public class PetShelterContext : DbContext
{
public PetShelterContext(DbContextOptions options) : base(options) { }
public DbSet<Pet> Pets { get; set; }
public DbSet<Owner> Owners { get; set; }
}
}
Replace
public int OwnerId { get; set; }
with
public int? OwnerId { get; set; }
and fix properties ( the attributes are optional for net5)
public class Owner
{
.......
[InverseProperty(nameof(Pet.Owner))]
public virtual ICollection<Pet> Pets { get; set; }
.....
}
and maybe here too
public class Pet
{
.....
public int OwnerId { get; set; }
[ForeignKey(nameof(OwnerId))]
[InverseProperty("Pets")]
public Owner Owner { get; set; }
}
Related
I have a problem with related entities deletion. For example, I need to delete one of series from user series collection. When this happens I want all of related to this series records in database to be deleted. How to do it? Please provide example, I'm stuck a little. Thank you!
public class User
{
public Guid UserId { get; set; }
public virtual List<Series> UserSeries { get; set; }
}
public class DropPhoto
{
public Guid DropPhotoId { get; set; }
public virtual SimpleLine SimpleHorizontalLine { get; set; }
public virtual SimpleLine SimpleVerticalLine { get; set; }
public virtual Drop Drop { get; set; }
}
public class ReferencePhoto
{
public Guid ReferencePhotoId { get; set; }
public virtual SimpleLine SimpleLine { get; set; }
}
public class Series
{
public Guid SeriesId { get; set; }
public virtual List<DropPhoto> DropPhotosSeries { get; set; }
public virtual ReferencePhoto ReferencePhotoForSeries { get; set; }
}
public class SimpleLine
{
public Guid SimpleLineId { get; set; }
}
public class Drop
{
public Guid DropId { get; set; }
}
You are actually looking for cascade delete.
For details please look at https://www.entityframeworktutorial.net/code-first/cascade-delete-in-code-first.aspx
Here is an example
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public virtual StudentAddress Address { get; set; }
}
public class StudentAddress
{
[ForeignKey("Student")]
public int StudentAddressId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public int Zipcode { get; set; }
public string State { get; set; }
public string Country { get; set; }
public virtual Student Student { get; set; }
}
The following example demonstrates the cascade delete operation
using (var ctx = new SchoolContext())
{
var stud = new Student() { StudentName = "James" };
var add = new StudentAddress() { Address1 = "address" };
stud.Address = add;
ctx.Students.Add(stud);
ctx.SaveChanges();
ctx.Students.Remove(stud);// student and its address will be removed from db
ctx.SaveChanges();
}
I have problem when I try to migrate my model in EF Core 2.0.
public class Profile
{
[Key]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public ExternalUser User { get; set; }
}
public class OrganizationCustomerProfile : Profile
{
public string CompanyName { get; set; }
public Address LegalAddress { get; set; }
public Address ActualAddress { get; set; }
public BusinessRequisites Requisites { get; set; }
public string President { get; set; }
public IEnumerable<ContactPerson> ContactPerson { get; set; }
}
public class PersonCustomerProfile : Profile
{
public FullName Person { get; set; }
public Address Address { get; set; }
public string PhoneNumber { get; set; }
}
public class ContactPerson
{
[Key]
public Guid Id { get; set; }
public FullName Person { get; set; }
public string Rank { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public Guid ProfileId { get; set; }
public Profile Profile { get; set; }
}
Here I want to add complex datatypes Address and BusinessRequisites, which are:
public class BusinessRequisites
{
public string OGRN { get; set; }
public string INN { get; set; }
public string KPPCode { get; set; }
public string SettlementAccount { get; set; }
public string RCBIC { get; set; }
public string CorrespondentAccount { get; set; }
public string BankName { get; set; }
}
public class Address
{
public string FullAddress { get; set; }
public float Latitude { get; set; }
public float Longtitude { get; set; }
}
Code which I use for TPH binding:
public DbSet<Profile> UserProfiles { get; set; }
public DbSet<ContactPerson> ContactPerson { get; set; }
public DbSet<OrganizationCustomerProfile> OrganizationCustomerProfile { get; set; }
...
modelBuilder.Entity<Profile>().HasKey(u => u.Id);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.ActualAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.LegalAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.Requisites);
But when I try to make a migration, I get an error:
"Cannot use table 'UserProfiles' for entity type
'OrganizationCustomerProfile.ActualAddress#Address' since it has a
relationship to a derived entity type 'OrganizationCustomerProfile'.
Either point the relationship to the base type 'Profile' or map
'OrganizationCustomerProfile.ActualAddress#Address' to a different
table."
So, what the reason of this error? Is it not possible to create hierarchy inheritance in EF Core 2.0?
Thank you!
It seems like this isn't supported at the moment:
https://github.com/aspnet/EntityFrameworkCore/issues/9888
I'm bulding an application and when I want to insert a form into my form table I get the following error:
Cannot insert explicit value for identity column in table 'Relation'
when IDENTITY_INSERT is set to OFF.
These are my models:
Form model:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("FormType")]
public int? TypeId { get; set; }
public virtual FormType Type { get; set; }
[ForeignKey("FormStatusType")]
public int? StatusTypeId { get; set; }
public virtual FormStatusType StatusTknype { get; set; }
[ForeignKey("Relation")]
public int? SupplierId { get; set; }
public virtual Relation Supplier { get; set; }
[ForeignKey("Relation")]
public int? CustomerId { get; set; }
public virtual Relation Customer { get; set; }
public String SupplierReference { get; set; }
public Guid ApiId { get; set; }
public DateTime DueDate { get; set; }
public FormFile FormFiles { get; set; }
public String FormName { get; set; }
public DateTime UploadDate { get; set; }
Relation model:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("FormType")]
public int? TypeId { get; set; }
public virtual FormType Type { get; set; }
[ForeignKey("FormStatusType")]
public int? StatusTypeId { get; set; }
public virtual FormStatusType StatusTknype { get; set; }
[ForeignKey("Relation")]
public int? SupplierId { get; set; }
public virtual Relation Supplier { get; set; }
[ForeignKey("Relation")]
public int? CustomerId { get; set; }
public virtual Relation Customer { get; set; }
public String SupplierReference { get; set; }
public Guid ApiId { get; set; }
public DateTime DueDate { get; set; }
public FormFile FormFiles { get; set; }
public String FormName { get; set; }
public DateTime UploadDate { get; set; }
My context looks like this:
public class DataContext: DbContext
{
public DataContext(DbContextOptions<DataContext> options): base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer();
}
public DbSet<Relation> Relation { get; set; }
public DbSet<Setting> Settings { get; set; }
public DbSet<Notification> Notification { get; set; }
public DbSet<FormStatusType> FormStatusType { get; set; }
public DbSet<File> File { get; set; }
public DbSet<FormFile> FormFile { get; set; }
public DbSet<FormType> FormType { get; set; }
public DbSet<Form> Form { get; set; }
public DbSet<User> User { get; set; }
public DbSet<RelationUser> RelationUser { get; set; }
public DbSet<SupplierCustomer> SupplierCustomer { get; set; }
}
The method I use to add a form looks like this:
public async Task<Form> AddForm(Form form, int currentUserId)
{
try
{
if (form != null)
{
//huidige gebruiker als supplier aanduiden
Relation r = await GetCurrentUser(currentUserId);
form.Supplier = r;
form.SupplierId = r.Id;
//form aan de db toevoegen
_datacontext.Form.Add(form);
_datacontext.SaveChanges();
return form;
}
else
{
return null;
}
}
catch (Exception e)
{
LogError(e);
return null;
}
}
The get current user method
private async Task<Relation> GetCurrentUser(int currentUserId)
{
var relation = from r in _datacontext.RelationUser
where r.UserId == currentUserId
select r.Relation;
return await relation.FirstOrDefaultAsync();
}
This is where I call the AddForm method:
[HttpPost]
[Route("addform")]
[Authorize]
// api/form/addform
public async Task<IActionResult> AddForm([FromBody] Form form)
{
if (ModelState.IsValid)
{
Form f = await _formRepository.AddForm(form, GetUserIdFromToken());
if(f != null)
{
QueueObject qo = new QueueObject()
{
ActionTypeId = 1,
FormId = f.Id
};
await new QueueHandler().SendMessageToQueue(qo);
}
return Ok(f);
}
else
{
return NotFound("model is niet geldig");
}
}
I already searched but found nothing that solved the problem
Another possible reason this may happen, is if you have a timeout in some call to SaveChanges when trying to insert new entities to your database, then try calling SaveChanges again, using the same DbContext instance.
This is reproducible:
using(var context = new MyDbContext())
{
context.People.Add(new Person("John"));
try
{
// using SSMS, manually start a transaction in your db to force a timeout
context.SaveChanges();
}
catch(Exception)
{
// catch the time out exception
}
// stop the transaction in SSMS
context.People.Add(new Person("Mike"));
context.SaveChanges(); // this would cause the exception
}
This last SaveChanges would cause Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF.
You have multiple errors on your model. The ForeignKey attribute must point to properties in the class, not to the type of the dependent entity:
//FORM MODEL
[ForeignKey("Type")]
public int? TypeId { get; set; }
public virtual FormType Type { get; set; }
[ForeignKey("StatusTknype")]
public int? StatusTypeId { get; set; }
public virtual FormStatusType StatusTknype { get; set; }
[ForeignKey("Supplier")]
public int? SupplierId { get; set; }
public virtual Relation Supplier { get; set; }
[ForeignKey("Customer")]
public int? CustomerId { get; set; }
public virtual Relation Customer { get; set; }
//RELATION MODEL
[ForeignKey("Type")]
public int? TypeId { get; set; }
public virtual FormType Type { get; set; }
[ForeignKey("StatusTknype")]
public int? StatusTypeId { get; set; }
public virtual FormStatusType StatusTknype { get; set; }
[ForeignKey("Relation")]
public int? SupplierId { get; set; }
public virtual Relation Supplier { get; set; }
[ForeignKey("Customer")]
public int? CustomerId { get; set; }
public virtual Relation Customer { get; set; }
Also, if you followed Convention Over Configuration, you could drop the ForeignKeyAttribute completely by just naming the properties conventionally:
public int? StatusTypeId { get; set; }
public virtual FormStatusType StatusType { get; set; }
I am trying to add an entry to a table that holds a users browsing history information. However, when trying to save the addition an SqlException is thrown:
Cannot insert duplicate key row in object 'dbo.AspNetUsers' with
unique index 'UserNameIndex'. The duplicate key value is
(exampleUserName). The statement has been terminated.
A user is has many browsing histories but a browsing history can only be attached to one user so there is a user as part of the BrowsingHistory DataModel:
namespace DataModels
{
[Table("BrowsingHistory")]
public class BrowsingHistory
{
[Key]
public int BrowsingHistoryId { get; set; }
public int ProductId { get; set; }
public System.DateTime DateTime { get; set; }
public int DeviceId { get; set; }
public int UserId { get; set; }
public virtual AspNetUsers User { get; set; }
public virtual Device Device { get; set; }
public virtual Product Product { get; set; }
}
}
It is to note that I am using the Microsoft Identity classes for my authentication. The user class looks as follows:
namespace DataModels
{
using System;
using System.Collections.Generic;
[Table("AspNetUsers")]
public class AspNetUsers
{
public AspNetUsers()
{
BrowsingHistories = new HashSet<BrowsingHistory>();
Orders = new HashSet<Order>();
AspNetUserClaims = new HashSet<AspNetUserClaims>();
AspNetRoles = new HashSet<AspNetRoles>();
}
[Key]
public int Id { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public DateTime? LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string UserName { get; set; }
public string HouseName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string Town { get; set; }
public string County { get; set; }
public string Postcode { get; set; }
public string ContactNumber { get; set; }
public virtual ICollection<BrowsingHistory> BrowsingHistories { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual ShoppingCart ShoppingCart { get; set; }
public virtual ICollection<AspNetUserClaims> AspNetUserClaims { get; set; }
public virtual ICollection<AspNetRoles> AspNetRoles { get; set; }
}
}
The error occurs when trying to save the addition in the repository. On the _context.SaveChanges() line the method below.
public void CreateBrowsingHistoryEntry(BrowsingHistory bhe)
{
_context.BrowsingHistory.Add(bhe);
_context.SaveChanges();
}
Any help with this issue would be greatly appreciated.
When I'm using the following code, the tables are generated successfully with the Primary key and Foreign Key relations.
[Table("tblDepartments")]
public class DepartmentModel
{
[Key]
public int DepartmentID { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<EmployeeModel> Employees { get; set; }
}
[Table("tblEmployees")]
public class EmployeeModel
{
[Key]
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public virtual DepartmentModel DID { get; set; }
}
But when I use the following Code, I'm Getting error:
[Table("tblDepartments")]
public class DepartmentModel
{
[Key]
public int DepartmentID { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<EmployeeModel> Employees { get; set; }
}
[Table("tblEmployees")]
public class EmployeeModel
{
[Key]
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
[ForeignKey("DeptID")]
public virtual DepartmentModel DID { get; set; }
}
ERROR:
The ForeignKeyAttribute on property 'DID' on type
'MvcApplication1.Models.EmployeeModel' is not valid. The foreign key
name 'DeptID' was not found on the dependent type
'MvcApplication1.Models.EmployeeModel'. The Name value should be a
comma separated list of foreign key property names.
Please Help. Thanks in advance.
The problem is with your EmployeeModel as you are missing departmentid field in your table as suggested by Gert. you can use the below for EmployeeModel
[Table("tblEmployees")]
public class EmployeeModel
{
[Key]
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public int DeptID { get; set; } //<-- You forgot to add this
[ForeignKey("DeptID")]
public virtual DepartmentModel DID { get; set; }
}
Put the foreign key as a property inside your model then have the navigation property point to it.
public class EmployeeModel
{
[Key]
public int ID { get; set; }
public int DeptID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
[ForeignKey("DeptID")]
public virtual DepartmentModel DID { get; set; }
}
In '[ForeignKey("DeptID")]' you need to have the property DeptID in the model.
If you don't want it but just the name DeptID on the foreign key field you need to use fluent interface to configure the relationship i.e.
HasOptional(t => t.DID)
.WithMany()
.Map(d => d.MapKey("DeptID"));