Code First Cascade Delete Not Using Fluent API - c#

I have these two entities
class AUT
{
public Guid ID { get; set; }
public string Name { get; set; }
public Engineer Engineer { get; set; }
}
class InstallationSetup
{
public virtual AUT ApplicationUnderTesting { get; set; }
public Guid ID { get; set; }
// Loads of properties etc
}
class Engineer
{
public Guid ID { get; set; }
public string Name { get; set; }
}
Using code first and some data annotations these entities create a database. I'm using EF 5, When I delete an Application, it should only delete itself and any InstallationSetup that has been referenced to it. It shouldn't delete the Engineer. However when I do try and delete it, I get the error:
The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.InstallationSetups_dbo.AUTs_ApplicationUnderTesting_ID". The conflict occurred in database "UXLab", table "dbo.InstallationSetups", column 'ApplicationUnderTesting_ID'.
The statement has been terminated.
So, I'm guessing that because there is another table with an entry relying on the AUT to be there, by deleting the AUT you will leave InstallationSetup with null foreign key thus a broken row.
I should be able to (preferably not using Fluent API) tell entity framework that any thing that has a reference to AUT should also be deleted? This is what I want to achieve.

you just have to add a column that is similar as your generated Foreign key column, when entity framework generates this FK column it set cascading delete to disabled.
class AUT
{
public Guid ID { get; set; }
public string Name { get; set; }
public Engineer Engineer { get; set; }
}
class InstallationSetup
{
public virtual AUT ApplicationUnderTesting { get; set; }
public int ApplicationUnderTestingId {get; set;} <--- Add this.
public Guid ID { get; set; }
// Loads of properties etc
}
class Engineer
{
public Guid ID { get; set; }
public string Name { get; set; }
}
If you generate your database again, you see that some things are changed. The automatically generated column AUTs_ApplicationUnderTesting_ID is no longer there and the ApplicationUnderTestingId column is now used for your foreign key relationship.
EF will enable cascading delete automatically now.

Related

Receiving error "The entity type requires a primary key to be defined" for a list with a key defined

I have two classes Pick and PickList. I have successfully added a single Pick to the database, but now I want to add multiple Picks in a PickList to be added to the database in a single call. I keep receiving the error
The entity type 'PickList' requires a primary key to be defined. If
you intended to use a keyless entity type, call 'HasNoKey' in
'OnModelCreating'. For more information on keyless entity types, see
https://go.microsoft.com/fwlink/?linkid=2141943.
I tried making PickList Keyless, which did not work and resulted in the error
System.InvalidOperationException: Unable to track an instance of type
'PickList' because it does not have a primary key. Only entity types
with a primary key may be tracked.
I cannot find an example in the Microsoft documentation of adding a List to the database.
Pick
public class Pick
{
[Key]
public string? Username { get; set; }
public string? Game { get; set; }
public string? Selection { get; set; }
}
PickList
public class PickList
{
[Key]
public List<Pick>? Picks { get; set; }
}
DBContext
public DbSet<PickList>? Selections { get; set; }
Program
app.MapPost(
"/selections", async (PickList pick, DataContext db) => {
db.Selections?.Add(pick);
await db.SaveChangesAsync();
return Results.Ok();
}
The best option for the Primary keys is numbers. So it would be better to fix the models a bit and make a new migration. Try using the models this way.
Of course, you can also use strings for primary keys, but you have no benefit from this, except slower search in the database. If the entities are too many and the int or long are too shorts, you can use Guid
public class Pick
{
[Key]
public int Id { get; set; }
public string? Username { get; set; }
public string? Game { get; set; }
public string? Selection { get; set; }
}
public class PickList
{
public PickList()
{
this.Picks = new HashSet<Pick>();
}
[Key]
public int Id { get; set; }
public IColection<Pick>? Picks { get; set; }
}

All containing foreign keys must be removed or redefined before the property can be removed - EF Core

I am getting the above error when trying to add migration after add a foreign key using Entity Framework core.
I am adding FK in
public class ApplicantDetail
{
[Key]
public int Id { get; set; }
[ForeignKey("GrantProgramFK")]
public GrantProgram GrantProgramId { get; set; }
--------
}
This FK ties to class
public class GrantProgram
{
[Key]
public int Id { get; set; }
-----
}
Any help is appreciated. I tried to remove the entity and run migration again, but failed.
Full error:
The property 'GrantProgramId' cannot be removed from entity type 'EFDataAccessLibrary.Models.ApplicantDetail' because it is being used in the foreign key {'GrantProgramId'} on 'EFDataAccessLibrary.Models.ApplicantDetail'. All containing foreign keys must be removed or redefined before the property can be removed
I found a page,
click here, but what does that mean? how to resolve it.
I had the same problem. I solved it by removing the "id" in the foreign key:
public class ApplicantDetail
{
[Key]
public int Id { get; set; }
[ForeignKey("GrantProgramFK")]
public GrantProgram GrantProgram { get; set; }
--------
}
I still don't know why. If anybody can explain, or give a solution to leave "id" in it, don't hesitate to tell us.
Since entityframework auomatically uses any identifoer ending with 'ID or Id or id', ensure no other property name ends with 'ID or Id or id'
I'd recommend to delete previous migrations file in the solution, this works for me
I was getting the same error, in my case all I did was undo the changes in AppDbContextModelSnapshot file (you can also delete the file) which is created in the migrations folder.
Turns out I had made an error before performing the migration, after which a model snapshot of my AppDbContext was created. After fixing the error, I tried the migration again, but the AppDbContextModelSnapshot was already modified, EF was not allowing to override with the same key of the same model (in this case GrantProgramFK from GrantProgram model) . So just undo the changes in your AppDbContextModelSnapshot file and perform the migration again.
I was able to solve the issue by going into ModelSnapShot.cs in the Migrations folder and making sure to delete all references to the property causing issues. You'll be looking for any references to 'GrantProgramIdId'.
Make sure to delete any lines where the snapshot creates foreign keys.
Change any instance where the property name includes the incorrect property name above.
Make sure you check the entire file. There should be two separate places where issues exist.
Also, delete any migrations where this property was included, then create a new migration and should be good to go.
I had a same issue. You have to delete(remove migration did not work either so I deleted manually) the migration and snapshot and change this field:
public GrantProgram GrantProgramId { get; set; }
to
public int GrantProgramId { get; set; }
You have to fix your classes before migration:
public class ApplicantDetail
{
[Key]
public int Id { get; set; }
public int? GrantProgramId { get; set; }
[ForeignKey("GrantProgramId")]
[InverseProperty("ApplicantDetails")]
public GrantProgram GrantProgram{ get; set; }
--------
}
public class GrantProgram
{
[Key]
public int Id { get; set; }
[InverseProperty(nameof(ApplicantDetail.GrantProram))]
public virtual ICollection<ApplicantDetail> ApplicantDetails{ get; set; }
-----
}
Add data annotations and everything will work smooth, see
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name ="Address Id")]
public int AddressId { get; set; }
public string Street { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public int? StateId { get; set; }
public string Country { get; set; } = string.Empty;
public string ZipCode { get; set; } = string.Empty;
}
public class State
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name ="State Id")]
public int StateId { get; set; }
public string StateName { get; set; } = string.Empty;
}

C# Entity Framework : Rename table field without losing data, using automatic migrations

I am using Entity Framework's automatic migrations with a code-first approach.
I dont use the packet manager console and dont have access to coded migrations.
I have a line representing my table in my model here :
public virtual DbSet<Customer> Customers { get; set; }
I renamed one of the fields of Customer :
[Table("Customers")]
public partial class Customer
{
[Key]
[Column(TypeName = "numeric")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int idCustomer { get; set; }
public string name { get; set; }
public int age { get; set; }
public string mail { get; set; }
public string password { get; set; }
}
I just changed "mail" to "mailModified".
But when the database got updated, Entity deleted all data from the name field.
I think it deleted my column to create a new one with the new name.
How to avoid that ? How to make him understand to only rename the column ?
Thanks for any participation
You have to do it using Migration commands.. so that data won't be lost ..
Else u can add the following code to auto-generated up and down method
RenameColumn("dbo.MyTable", "NewColumn", "OldColumn");
Try using Column Attribute when you create your table class
class Table
{
[Column("ColumnName")]
public int Column1 { get; set; }
[Column("ColumnName")]
public int Column2 { get; set; }
}

Surprising naming in table with two foreign keys to the same table

I have the following entity (which was created using database-first). It has two foreign keys to the AspNetUser table.
public partial class Message
{
public int Id { get; set; }
public string ToUserId { get; set; }
public string FromUserId { get; set; }
public string Message1 { get; set; }
public bool Viewed { get; set; }
public System.DateTime TimeStampUtc { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
public virtual AspNetUser AspNetUser1 { get; set; }
}
I find that AspNetUser corresponds to FromUserId, and AspNetUser1 corresponds to ToUserId. This surprises me since ToUserId is defined first in the table, I'd expect the 1 to be appended to the one that comes second.
I can code for it either way, but I can't code for it if the rules are somewhat random as to how this is determined. It's critical that I understand the rules and know which one will be associated with which foreign key.
Does anyone know the rules involved here?
In your edmx you can rename the navigation properties by clicking on the property and changing the Name. This will survive EDMX updates. However, if you totally delete it from EDMX and then build it from the database again, then in that case you will need to rename it again. Otherwise, you should be fine.

Unable to determine the principal end of an association - Entity Framework Model First

I have created Entity Data Model in Visual Studio. Now I have file with SQL queries and C# classes generated from Model.
Question:
Classes are generated without annotations or code behind (Fluent API). Is it OK? I tried to run my application but exception was thrown:
Unable to determine the principal end of an association between the types 'Runnection.Models.Address' and 'Runnection.Models.User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I read that I can not use Fluent API with "Model First". So what can I do?
Code:
User
public partial class User
{
public User()
{
this.Events = new HashSet<Event>();
this.CreatedEvents = new HashSet<Event>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Photo { get; set; }
public int EventId { get; set; }
public string Nickname { get; set; }
public OwnerType OwnerType { get; set; }
public NetworkPlaceType PlaceType { get; set; }
public virtual ICollection<Event> Events { get; set; }
public virtual Address Address { get; set; }
public virtual ICollection<Event> CreatedEvents { get; set; }
public virtual Owner Owner { get; set; }
}
Address
public partial class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
Context
//Model First does not use this method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>().HasRequired(address => address.User)
.WithRequiredDependent();
modelBuilder.Entity<User>().HasRequired(user => user.Address)
.WithRequiredPrincipal();
base.OnModelCreating(modelBuilder);
}
You have to specify the principal in a one-to-one relationship.
public partial class Address
{
[Key, ForeignKey("User")]
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
By specifying a FK constraint, EF knows the User must exists first (the principal) and the Address follows.
Further reading at MSDN.
Also, see this SO answer.
Updated from comments
In the designer, select the association (line between Users & Address). On the properties window, hit the button with the [...] on Referential Constraint (or double click the line). Set the Principal as User.
Error:
Had same error of "Unable to determine the principal end of an association between the types 'Providence.Common.Data.Batch' and 'Providence.Common.Data.Batch'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.".
HOWEVER, note that this is the SAME table.
Cause: My database was MS SQL Server. Unfortunately when MS SQL Server's Management Studio adds foreign keys, it adds the default foreign key as Batch ID column of Batch table linking back to itself. You as developer are suppose to pick another table and id to truly foreign key to, but if you fail to it will still allow entry of the self referencing FK.
Solution:
Solution was to delete the default FK.
Cause 2: Another situation is that the current table may be fixed but the old historical image of the table when the EF's edmx was done had the default FK.
Solution 2: is to delete the table from the Model Browser's Entity Types list and click "yes" and then "Update Model from the Database" again.

Categories

Resources