Entity Framework DELETE statement conflicted with the REFERENCE constraint - entity-framework

I’m pretty new to EF and I have a little problem.
I just want to delete an item in my database. I’m using SQL Server 2012 Express, VS2012, AdventureWorks 2012.
The query that I execute is the following:
context = new AWEntities();
var removedItem = context.Addresses
.Include("StateProvince")
.Include("SalesOrderHeaders")
.Include("BusinessEntityAddresses").Single(d => d.AddressID == 11);
context.Addresses.Remove(removedItem);
context.SaveChanges();
The error that I get is
The DELETE statement conflicted with the REFERENCE constraint "FK_SalesOrderHeader_Address_ShipToAddressID". The conflict occurred in database "AdventureWorks2012", table "Sales.SalesOrderHeader", column 'ShipToAddressID'.
The statement has been terminated.
Is this actually a good way to delete items and the according entries in the other tables?
Please point me into the right direction.
public partial class Address
{
public Address()
{
this.BusinessEntityAddresses = new HashSet<BusinessEntityAddress>();
this.SalesOrderHeaders = new HashSet<SalesOrderHeader>();
}
public int AddressID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public int StateProvinceID { get; set; }
public string PostalCode { get; set; }
public System.Data.Spatial.DbGeography SpatialLocation { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual StateProvince StateProvince { get; set; }
public virtual ICollection<BusinessEntityAddress> BusinessEntityAddresses { get; set; }
public virtual ICollection<SalesOrderHeader> SalesOrderHeaders { get; set; }
}
public partial class StateProvince
{
public StateProvince()
{
this.Addresses = new HashSet<Address>();
this.SalesTaxRates = new HashSet<SalesTaxRate>();
}
public int StateProvinceID { get; set; }
public string StateProvinceCode { get; set; }
public string CountryRegionCode { get; set; }
public bool IsOnlyStateProvinceFlag { get; set; }
public string Name { get; set; }
public int TerritoryID { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual CountryRegion CountryRegion { get; set; }
public virtual ICollection<SalesTaxRate> SalesTaxRates { get; set; }
public virtual SalesTerritory SalesTerritory { get; set; }
}
}
public partial class BusinessEntityAddress
{
public int BusinessEntityID { get; set; }
public int AddressID { get; set; }
public int AddressTypeID { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual Address Address { get; set; }
public virtual AddressType AddressType { get; set; }
public virtual BusinessEntity BusinessEntity { get; set; }
}
public partial class SalesOrderHeader
{
public SalesOrderHeader()
{
this.SalesOrderDetails = new HashSet<SalesOrderDetail>();
this.SalesOrderHeaderSalesReasons = new HashSet<SalesOrderHeaderSalesReason>();
}
public int SalesOrderID { get; set; }
public byte RevisionNumber { get; set; }
public System.DateTime OrderDate { get; set; }
public System.DateTime DueDate { get; set; }
public Nullable<System.DateTime> ShipDate { get; set; }
public byte Status { get; set; }
public bool OnlineOrderFlag { get; set; }
public string SalesOrderNumber { get; set; }
public string PurchaseOrderNumber { get; set; }
public string AccountNumber { get; set; }
public int CustomerID { get; set; }
public Nullable<int> SalesPersonID { get; set; }
public Nullable<int> TerritoryID { get; set; }
public int BillToAddressID { get; set; }
public int ShipToAddressID { get; set; }
public int ShipMethodID { get; set; }
public Nullable<int> CreditCardID { get; set; }
public string CreditCardApprovalCode { get; set; }
public Nullable<int> CurrencyRateID { get; set; }
public decimal SubTotal { get; set; }
public decimal TaxAmt { get; set; }
public decimal Freight { get; set; }
public decimal TotalDue { get; set; }
public string Comment { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual Address Address { get; set; }
public virtual ShipMethod ShipMethod { get; set; }
public virtual CreditCard CreditCard { get; set; }
public virtual CurrencyRate CurrencyRate { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<SalesOrderDetail> SalesOrderDetails { get; set; }
public virtual SalesPerson SalesPerson { get; set; }
public virtual SalesTerritory SalesTerritory { get; set; }
public virtual ICollection<SalesOrderHeaderSalesReason> SalesOrderHeaderSalesReasons { get; set; }
}

Can't really tell much from what you have said, but you may benefit from looking into using the DbModelBuilder to solve cascade issues:
modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOptional(x => x.Parent)
.WillCascadeOnDelete(true);
Again, would need more information about your model structure to determine if this is the right approach.
Either that or in your delete method, remove any children first, and then remove the parent.

modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOptional(x => x.Parent)
.WillCascadeOnDelete(true);
or use Include
var adv = db.Adv.Include(b => b.Features)
.Include(b => b.AdvDetails)
.Include(b => b.AdvGallery)
.FirstOrDefault(b => b.Id == id);
db.Adv.Remove(adv);
for .HasMany(...).WithMany(...) Include is ok

You can resolve this issue on SQL side
Method 1 :
First, you need to find on which table this FK constraint has been defined, through using Replication monitor.
Right click on that FK, click Modify, you should get popup box like one shown below.
From the popup box, Select Cascade for del.
Method 2 :
set ON DELETE CASCADE in sql at the end of constraint.

In EF Core the syntax in builder is as follows:
builder.HasOne(b => b.Parent )
.WithMany(a => a.Children)
.OnDelete(DeleteBehavior.Cascade);
https://learn.microsoft.com/en-us/ef/core/saving/cascade-delete

I got this error when I created Entity B, that referenced Entity A, and then tried to delete Entity A. SQL/EF did not allow me to leave that dangling Id reference, since the objcet no longer existed. Cascading deletes would solve this, but I wanted B to persist. So I have to remove the reference from B before deleting A:
var existingContractApprovers = _repo.Query<ChangeOrderApproverForContract>().Where(coafc => coafc.ContractId == key).ToList();
//remove refs to contract approvers to preserve data integrity
foreach(var contractApp in existingContractApprovers)
{
var associatedChangeOrderApprovers = _repo.Query<ChangeOrderApprover>().AsNoTracking().Where(coafc => coafc.ChangeOrderApproverForContractId == contractApp.Id).ToList();
foreach(var coApp in associatedChangeOrderApprovers)
{
_repo.Edit(coApp);
coApp.ChangeOrderApproverForContractId = null;
}
}
_repo.SaveChanges();
//remove the contract approvers
foreach (var contractApp in existingContractApprovers)
{
_repo.Delete(contractApp);
}
_repo.SaveChanges();

You can do this in EF Core.
modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOne(s => s.Parent)
.OnDelete(DeleteBehavior.Cascade);
The safer alternative is to make sure all children are deleted before deleting the parent. You should cascade on delete only if you are completely aware of how your entities relate. For example, you could have lots of orders connected to
a certain category in your e-commerce store. Once the category is deleted, all the orders and any entity whose foreign keys are connected to this parent category will be gone.

Related

Entity Framework - unwanted population of related entity

Given
public class Customer
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
public bool IsSubscribed { get; set; }
public MembershipType MembershipType { get; set;}
public byte MembershipTypeId { get; set; }
}
why does
onDb = _context.Customers.Single(c => c.Id == customer.Id);
populate the MembershipType object??? I don't want that to happen.
Is it because I have loaded the customer with the same ID before?

EF Core More Navigation properties from two tables

I am trying to create navigation properties for two table.
Here is the code.
public class CourseMaster
{
public int Id { get; set; }
public string Name { get; set; }
public int? TeamLeaderId { get; set; }
[ForeignKey("TeamLeaderId")]
public StudentMaster TeamLeader { get; set; }
public int? GroupLeaderId { get; set; }
[ForeignKey("GroupLeaderId")]
public StudentMaster GroupLeader { get; set; }
public virtual ICollection<StudentMaster> Students { get; set; }
}
public class StudentMaster
{
public int id { get; set; }
public string Name { get; set; }
public int FirstSemCourseId { get; set; }
[ForeignKey("FirstSemCourseId")]
public CourseMaster FirstSemCourse { get; set; }
public int SecondSemCourseId { get; set; }
[ForeignKey("SecondSemCourseId")]
public CourseMaster SecondSemCourse { get; set; }
public int ThirdSemCourseId { get; set; }
[ForeignKey("ThirdSemCourseId")]
public CourseMaster ThirdSemCourse { get; set; }
public int CourseMasterId { get; set; }
public CourseMaster Course { get; set; }
}
// Fluent API
modelBuilder.Entity<StudentMaster>()
.HasOne(p => p.Course)
.WithMany(b => b.Students)
.HasForeignKey(p => p.CourseMasterId);
But when i am creating migrations i am getting following error.
Unable to determine the relationship represented by navigation property 'CourseMaster.TeamLeader' of the type 'StudentMaster'. Either manually configure the relationship, or ignore this property from model.
Whether the procedure i am following is right or should i create intermediate class.
or how should i create class.
Any help are appreciated.
Thanks

Invalid column name - one-to-many relation - Entity Framework

I have an entity with two foreign keys only on one of them I get an exception:
Invalid column name LookUpTypId
Both have the same code, but only one of them cause exception
public class Term
{
public Term ()
{
RequestTimes = new HashSet<RequestTime>();
}
public decimal Id { get; set; }
public string AcademicYear { get; set; }
public string Semester { get; set; }
public int? NumberOfDays { get; set; }
public bool Active { get; set; }
public bool Reserve { get; set; }
public string Description { get; set; }
public virtual ICollection<RequestTime> RequestTimes { get; set; }
}
public class LookUp
{
public LookUp()
{
RequestTimes = new HashSet<RequestTime>();
}
public int Id { get; set; }
public string Group { get; set; }
public string Key { get; set; }
public string Value { get; set; }
public virtual ICollection<RequestTime> RequestTimes { get; set; }
}
public class RequestTime
{
public decimal Id { get; set; }
public DateTime FromTime { get; set; }
public DateTime ToTime { get; set; }
public int RequestMaxNumber { get; set; }
public virtual int LookUpTypId { get; set; }
public virtual decimal TermId { get; set; }
[ForeignKey("TermId")]
public virtual Term Term { get; set; }
[ForeignKey("LookUpTypId")]
public virtual LookUp LookUp { get; set; }
}
//relationship in RequestTimeMap
this.HasRequired<LookUp>(rt => rt.LookUp)
.WithMany(lk => lk.RequestTimes)
.HasForeignKey(rt => rt.LookUpTypId);
this.HasRequired<Term>(rt => rt.Term)
.WithMany(t => t.RequestTimes)
.HasForeignKey(rt => rt.TermId);
Thank you
As I understand, the ForeignKey attribute should be used in the property that represents your foreign key.
If you have a object as a property, it should be right above it... unless you also have a separate property for it's Id. In that case, you should use the attribute above the Id property.
[ForeignKey("LookUpTypId")]
public virtual int LookUpTypId { get; set; }
[ForeignKey("TermId")]
public virtual decimal TermId { get; set; }
public virtual Term Term { get; set; }
public virtual LookUp LookUp { get; set; }
And... is this ID decimal?

Entity Framework, configuration for reading and writing

Given the following database model
I have two fluent entity framework configurations, one that works when I read (the setupFields list is set) and the other for writing, which if I use for reading as well, always comes with an empty SetupFields list
[Table("[BALANCE.SETUP]")]
public class SetupEntity
{
[Key]
public Guid Id { get; set; }
public string Title { get; set; }
public virtual ChassisEntity Chassis { get; set; }
public virtual EventEntity Event { get; set; }
public virtual ICollection<SetupFieldEntity> SetupFields { get; set; }
}
[Table("[BALANCE.SETUP.FIELD]")]
public class SetupFieldEntity
{
[Key]
[Column(Order = 0)]
public Guid SetupId { get; set; }
[Key]
[Column(Order = 1)]
public int Sequence { get; set; }
public string Section { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual SetupEntity Setup { get; set; }
}
(can read)
modelBuilder.Entity<SetupEntity>()
.HasMany(x => x.SetupFields)
.WithRequired(x => x.Setup)
.Map(x => x.MapKey("SETUPID"));
(can write)
modelBuilder.Entity<SetupEntity>()
.HasMany(x => x.SetupFields)
.WithRequired()
.HasForeignKey(x => x.SetupId);
If I use the read configuration to read, this is the error I get:
The column name 'SETUPID' is specified more than once in the SET clause. A column cannot be assigned more than one value in the same SET clause. Modify the SET clause to make sure that a column is updated only once. If the SET clause updates columns of a view, then the column name 'SETUPID' may appear twice in the view definition.
UPDATE 1
Just to make things clear, the models are lazy loaded and I'm explicitly inclucing them, so, when using the first connfiguration the models are set as expected:
if (includeFields)
{
x = x.Include(entity => entity.SetupFields);
}
UPDATE 2
Based on the comments bellow I change the mappings to have just this which works when inserting but when reading the child collection is still null:
modelBuilder.Entity<SetupEntity>().HasMany(x => x.SetupFields);
[Table("[BALANCE.SETUP]")]
public class SetupEntity
{
[Key]
public Guid Id { get; set; }
public string Title { get; set; }
public virtual ChassisEntity Chassis { get; set; }
public virtual EventEntity Event { get; set; }
public virtual ICollection<SetupFieldEntity> SetupFields { get; set; }
}
[Table("[BALANCE.SETUP.FIELD]")]
public class SetupFieldEntity
{
[Key]
[Column(Order = 0)]
public Guid SetupId { get; set; }
[Key]
[Column(Order = 1)]
public int Sequence { get; set; }
public string Section { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual SetupEntity Setup { get; set; }
}
UPDATE 3
Based on the comments I completelly removed the attributes from the entities, but the collection property is still null :(
public class SetupEntity
{
public Guid Id { get; set; }
public string Title { get; set; }
public virtual ChassisEntity Chassis { get; set; }
public virtual EventEntity Event { get; set; }
public virtual ICollection<SetupFieldEntity> SetupFields { get; set; }
}
[Table("[BALANCE.SETUP.FIELD]")]
public class SetupFieldEntity
{
public Guid SetupId { get; set; }
public int Sequence { get; set; }
public string Section { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual SetupEntity Setup { get; set; }
}
modelBuilder.Entity<SetupEntity>()
.HasKey(x => x.Id)
.HasMany(x => x.SetupFields)
.WithRequired(x => x.Setup);
modelBuilder.Entity<SetupFieldEntity>()
.HasKey(x => x.SetupId)
.HasKey(x => x.Sequence);

EF code first model not in sync with database

My EF Code First model for some reason is not in sync with the db. I'm getting this error:
{"Invalid column name 'Type_Id1'."}
The field is actually called 'Type_Id' so I'm not sure from where that 1 comes up. I have the table column called as Type_Id and also I've added a Type_Id in my type entity model.
Why might I be getting that error message, plus why I'm getting 1 at the end of the name?
Update
My Task class:
public class Task
{
public Task()
{
Language = 1;
Grades = new HashSet<Grade>();
Categories = new HashSet<Category>();
Subjects = new HashSet<Subject>();
Rooms = new Collection<Room>();
Tools = new Collection<Tool>();
}
[Key]
public int Id { get; set; }
public string Description { get; set; }
public virtual TaskType Type { get; set; }
public string Rules { get; set; }
[Required]
[StringLength(200), MinLength(1)]
public string Name { get; set; }
public int PreperationTime { get; set; }
public int InstructionTime { get; set; }
public int TaskTime { get; set; }
public int Type_Id { get; set; }
public string VideoLink { get; set; }
[Required]
public int Language { get; set; }
public int? MinimumParticipants { get; set; }
public int? MaximumParticipants { get; set; }
public int? Rating { get; set; }
[Required]
public string CreatedBy { get; set; }
public virtual ICollection<Grade> Grades { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subject> Subjects { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
}
DBContext class:
public ApplicationDbContext() : base("DefaultConnection", false)
{
}
public DbSet<Task> Tasks { get; set; }
public DbSet<TaskType> TaskTypes { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
You need to add the FK attribute on your navigation property. EF is creating Type_Id1 because Type_Id already exists (although it can't tell by convention it is the FK).
[ForeignKey("Type_Id")]
public virtual TaskType Type { get; set; }
https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships