Why does Entity Framework create a redundant foreign key? - sql

I have these 3 classes:
public class P
{
[Key]
[Column(Order = 0)]
[Required]
public string PId { get; set; }
}
public class E
{
[Key]
[ForeignKey("P")]
[Column(Order = 0)]
[Required]
public string PId { get; set; }
[Key]
[Column(Order = 1)]
[Required]
public string EId { get; set;
}
public class UF
{
[Key]
[Required]
public string Id { get; set; }
[ForeignKey("E")]
[Column(Order = 0)]
public string PId { get; set; }
[ForeignKey("E")]
[Column(Order = 1)]
public string EId { get; set; }
}
When running Entity Framework code-first, I expect to get something like this in the database:
But what I do get is the above + extra FK to PId:
i.e. in CREATE SCRIPT we get:
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_dbo.UF_dbo.E_PId_EId]') AND parent_object_id = OBJECT_ID(N'[dbo].[UF]'))
ALTER TABLE [dbo].[UF] WITH CHECK
ADD CONSTRAINT [FK_dbo.UF_dbo.E_PId_EId]
FOREIGN KEY([PId], [EId]) REFERENCES [dbo].[E] ([PId], [EId])
ON DELETE CASCADE
GO
But we also get this extra/redundant FK:
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_dbo.UF_dbo.P_PId]') AND parent_object_id = OBJECT_ID(N'[dbo].[UF]'))
ALTER TABLE [dbo].[UF] WITH CHECK
ADD CONSTRAINT [FK_dbo.UF_dbo.P_PId]
FOREIGN KEY([PId]) REFERENCES [dbo].[P] ([PId])
ON DELETE CASCADE
GO
Which results in this error when running the whole CREATE SCRIPT:
Introducing FOREIGN KEY constraint 'FK_dbo.UF_dbo.P_PId' on table 'UF' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Msg 1750, Level 16, State 0, Line 926
Could not create constraint or index. See previous errors.
The question is why?

your ids name is incorrect.
rename your id like this:
pubilc class P
{
public string Id { get; set; }
}
public class E
{
public string PId { get; set; }
//Entity Framework automatically recognizes it is a foreign key for P Table.
public string Id { get; set; }
//don't use EId , For Primary Key just use Id.
}
public class UF
{
public string Id { get; set; }
public string PId { get; set; }
public string EId { get; set; }
//For Foreign key just use: ClassName + Id
}

The answer was not in the question description unfortunately :/
There was an extra virtual memeber P that caused the extra FK:
//Shouldn't be here
public virtual P P { get; set; }
public virtual E E { get; set; }
Yeah Yeah...

Related

Two FK's pointing to the same column in another table

I have
public class Customer
{
public int Id { get; set; }
public int RepresentativeId { get; set; }
public int ChargeRepresentativeId { get; set; }
}
public class Representative
{
public int Id { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
Every Customer has its own Representative represented with RepresentativeId column, but also in certain scenarios I want to create new Customer with both RepresentativeId and its ChargeRepresentativeId.
I already have a FK constraint applied on RepresentativeId column
ALTER TABLE [Representatives] ADD CONSTRAINT [FK_Customers_Representatives]
FOREIGN KEY([RepresentativeId]) REFERENCES [Representative] ([Id])
How can I force ChargeRepresentativeId to be valid data which exists in the Representatives table (the case I already have for the RepresentativeId)?

EntityFramework Trying to create multiple links to the same table, FK Constraint error

I have a table called DeliveryRequest and another table called Operator, table DeliveryRequest is as follows:
public class DeliveryRequest
{
public int ID { get; set; }
public DateTime Date { get; set; }
public string UserID { get; set; }
public string Waybill { get; set; }
public string Reference { get; set; }
public int SupplierID { get; set; }
public Supplier Supplier { get; set; }
//[ForeignKey("Operator")]
public int SenderID { get; set; }
public Operator Sender { get; set; }
//[ForeignKey("Operator")]
public int ReceiverID { get; set; }
public Operator Receiver { get; set; }
public string Origin { get; set; }
public string Destination { get; set; }
public int ServiceID { get; set; }
public Service Service { get; set; }
}
And table Operator is as follows:
public class Operator
{
public int ID { get; set; }
public string Company { get; set; }
public int ContactID { get; set; }
public Contact Contact { get; set; }
public int AddressID { get; set; }
public Address Address { get; set; }
}
So the problem is, when I am trying to update my database I get a FK Constraint error as follows:
Introducing FOREIGN KEY constraint
'FK_dbo.DeliveryRequests_dbo.Operators_SenderID' on table
'DeliveryRequests' 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.
And the previous error is the same. As follows:
System.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN
KEY constraint 'FK_dbo.DeliveryRequests_dbo.Operators_SenderID' on
table 'DeliveryRequests' may cause cycles or multiple cascade paths.
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other
FOREIGN KEY constraints.
Focus on the Sender and Receiver part, I am no expert but the error must be there lol
//[ForeignKey("Operator")]
public int SenderID { get; set; }
public Operator Sender { get; set; }
//[ForeignKey("Operator")]
public int ReceiverID { get; set; }
public Operator Receiver { get; set; }
It looks like you are using Code First approach. So try to turn off CascadeDelete for DeliveryRequests:
modelBuilder.Entity<DeliveryRequests>()
.HasRequired(c => c.Operator )
.WithMany()
.WillCascadeOnDelete(false);
For example:
public class YourDBContext: DbContext
{
public YourDBContext(): base()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DeliveryRequests>()
.HasRequired(c => c.Operator )
.WithMany()
.WillCascadeOnDelete(false);
}
}

Foreign key may cause cycles or multiple cascade paths entity framework core

I am using Entity Framework core and I added a model called CourseOffering to my project. This model is related to other classes like Section. I successfully created a migration for it. The problem is when I try to apply the migration to the database. I get the following error:
Introducing FOREIGN KEY constraint 'FK_CourseOfferings_Sections_SectionId' on table 'CourseOfferings' 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 was trying to turn off cascade delete with FluentAPI, but I'm not entirely sure if that is the right solution to my problem. I mean is this totally safe to turn off cascade delete?
My CourseOffering model:
public class CourseOffering
{
public int Id { get; set; }
public Section Section { get; set; }
public Instructor Instructor { get; set; }
public Course Course { get; set; }
public AcademicSemester AcademicSemester { get; set; }
public int SectionId { get; set; }
public int InstructorId { get; set; }
public int? CourseId { get; set; }
public int AcademicSemesterId { get; set; }
}
My Section Model:
public class Section
{
public int Id { get; set; }
[Required]
[StringLength(10)]
public string Name { get; set; }
public int EntranceYear { get; set; }
public int StudentCount { get; set; }
public Department Department { get; set; }
public ProgramType Program { get; set; }
public AdmissionLevel AdmissionLevel { get; set; }
public ICollection<RoomSectionAssignment> RoomAssignments { get; set; }
public int DepartmentId { get; set; }
public int ProgramTypeId { get; set; }
public int AdmissionLevelId { get; set; }
public Section()
{
RoomAssignments = new Collection<RoomSectionAssignment>();
}
}
The migration created all the necessary foreign keys but there is cascade path that would cause cycles. I am not able to figure out what caused the cycle. Should I just turn off cascade delete with FluentAPI?
I was trying to turn off cascade delete with FluentAPI, but I'm not entirely sure if that is the right solution to my problem. I mean is this totally safe to turn off cascade delete?
Yes! This is the appropriate solution in this case! Moreover yes! This is completely safe to turn off cascade delete using FluentAPI because FluentAPIwill generate constraint on database too.

Petapoco can't update with non primary key identity

I am using AspNetIdentity and I have a non primary key column that is an identity auto increment.
[TableName("AspNetUsers")]
[PrimaryKey("Id", autoIncrement = false)]
public class Coach
{
public string Id { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public bool Active { get; set; }
public bool Admin { get; set; }
public int CoachId { get; set; }
}
How can I change my class definition to set CoachId to autoIncrement is false without it being the primary key? I'm using db.Save to save the object.
I just ended up executing a query!
var query = String.Format("UPDATE AspNetUsers SET Active = '{0}' WHERE Id='{1}'",activeStatus,id);

One-to-Many relation to existed table in EF6: The ALTER TABLE statement conflicted with the FOREIGN KEY constraint

So now I'm trying to use Code first approach with a couple of existed tables.
So before now I have an existed table with model:
[Table("Existed1")]
public class TimeSerieEntity
{
[Key]
[Column(Order = 0)]
[StringLength(3)]
public string TsId { get; set; }
[Key]
[Column(Order = 1, TypeName = "date")]
public DateTime Date { get; set; }
public double Value { get; set; }
}
And this entity illustrate time series element. So Now I need to add new Entity which has One-to-Many relation with this data. So I add class
public class TSRootEntity
{
[Key]
[StringLength(3)]
public string Code { get; set; }
public virtual ICollection<TimeSerieEntity> Values { get; set; }
}
and change TimeSerieEntity to this one:
[Table("Existed1")]
public class TimeSerieEntity
{
[Key, ForeignKey("TSMD")]
[Column(Order = 0)]
[StringLength(3)]
public string TsId { get; set; }
[Key]
[Column(Order = 1, TypeName = "date")]
public DateTime Date { get; set; }
public double Value { get; set; }
public virtual TSRootEntity TSMD { get; set; }
}
and add the following mapping:
`modelBuilder.Entity<TSRootEntity>()
.HasMany(c => c.Values)
.WithRequired(ts => ts.TSMD)
.WillCascadeOnDelete(false);
But when I trying to run migration it fails with error:
{"'PK_dbo.Existed1' is not a constraint.\r\nCould not drop constraint. See previous errors."}
Please, help me to fix this.
For some reason it's try to use PK_dbo.Existed1 but there is no such Constraint in DB, but there is PK_Existed1 Why EF add this dbo prefix?
UPD2:
I solved 1st problem just with renaming PK constraint. But now I have different exception:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Existed1_dbo.TSRootEntity_TsId". The conflict occurred in database "testdb", table "dbo.TSRootEntity", column 'Code'.
Ok. Found the problem. So last error caused because of Existed1 already have data, and TSRootEntity is empty. So it's try to map actuall foreign keys, to non existed primary keys. And that's make it fails.
So to solve that, we need prefill TSRootEntity as well. The question is - what is the most elegant way to do that?