Entity Framework Update Foreign Key constraint may cause multiple cascade paths - sql

I'm working on a project that is using entity framework and I'm getting the following error when I try and update my database.
Introducing FOREIGN KEY constraint 'FK_dbo.VisualManualWebPageFiles_dbo.VisualManualHeaders_VisualManualHeaderID' on table 'VisualManualWebPageFiles' 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.
Here are the classes that are being used for this.
First With a VisualManualHeader class.
<Table("VisualManualHeaders")>
Public Class VisualManualHeader
<Key>
Public Property VisualManualHeaderID As Integer
<Required>
Public Property Name As String
Public Overridable Property VisualManualPages As ICollection(Of VisualManualPage)
Public Overridable Property VisualManualWebPageFiles As ICollection(Of VisualManualWebPageFile)
End Class
Then a VisualManualHeader has the associated VisualManualPages with it like the following.
<Table("VisualManualPages")>
Public Class VisualManualPage
Enum VisualManualPageType
VIDEO
IMAGE
TEXT
WEBPAGE
End Enum
<Key>
Public Property VisualManualPageID As Integer
<Required>
Public Property Title As String
Public Property VisualManualHeaderID As Integer
<ForeignKey("VisualManualHeaderID")>
Public Overridable Property VisualManualHeader As VisualManualHeader
Public Property Content As String
Public Property PageType As VisualManualPageType
Public Overridable Property VisualManualWebPageFiles As ICollection(Of VisualManualWebPageFile)
End Class
The pages can then have many VisualManualWebPageFiles associated to the page.
<Table("VisualManualWebPageFiles")>
Public Class VisualManualWebPageFile
<Key>
Public Property VisualManualWebPageFileID As Integer
<Required>
Public Property VisualManualHeaderID As Integer
<ForeignKey("VisualManualHeaderID")>
Public Overridable Property VisualManualHeader As VisualManualHeader
<Required>
Public Property VisualManualPageID As Integer
<ForeignKey("VisualManualPageID")>
Public Overridable Property VisualManualPage As VisualManualPage
Public Property FileLocation As String
End Class
I have a feeling the problem is in the VisualManualWebPageFiles class due to the foreign key of the VisualManualHeader as if I remove this I can then update my project.
Thanks.

I think the problem lies with the association of the entity classes. Taking a look at your code seems that VisualManualHeader and VisualManualPage are in Many-To-Many relation; i.e. one instance of VisualManualHeader can be associated with many instances of VisualManualPage, and the the reverse is also true.
If that is indeed the case then, the relation between 2 classes are represented in VisualManualWebPageFile correctly and there is no need of keeping unnecessary properties in both VisualManualHeader, and VisualManualPage. I have tried to remove the same as follows:
VisualManualHeader
<Table("VisualManualHeaders")>
Public Class VisualManualHeader
<Key>
Public Property VisualManualHeaderID As Integer
<Required>
Public Property Name As String
Public Overridable Property VisualManualWebPageFiles As ICollection(Of VisualManualWebPageFile)
End Class
VisualManualPage
<Table("VisualManualPages")>
Public Class VisualManualPage
Enum VisualManualPageType
VIDEO
IMAGE
TEXT
WEBPAGE
End Enum
<Key>
Public Property VisualManualPageID As Integer
<Required>
Public Property Title As String
Public Property Content As String
Public Property PageType As VisualManualPageType
Public Overridable Property VisualManualWebPageFiles As ICollection(Of VisualManualWebPageFile)
End Class
VisualManualWebPageFile
<Table("VisualManualWebPageFiles")>
Public Class VisualManualWebPageFile
<Key>
Public Property VisualManualWebPageFileID As Integer
<Required>
Public Property VisualManualHeaderID As Integer
<ForeignKey("VisualManualHeaderID")>
Public Overridable Property VisualManualHeader As VisualManualHeader
<Required>
Public Property VisualManualPageID As Integer
<ForeignKey("VisualManualPageID")>
Public Overridable Property VisualManualPage As VisualManualPage
Public Property FileLocation As String
End Class

You are basically correct. The WebPageFiles does not need a reference to the ManualHeader table - and it actually could cause errors.
Example:
ManualPage ID 10 is owned by ManualHeader 1. You add WebPageFiles ID 15 with ManualPage 1 - but there is nothing stopping you setting WebPageFiles.ManualHeaderID to 3 as long as ManualHeader 3 exists. You now have a WebPageFile which a bit confused about who its grandparent is.
The correct way is to set the parent ID only (ManualPage). This parent will contain the ID of its own parent (ManualHeader) and so the child (WebPageFile) can unambiguously fing its grandparent via its parent.

Related

How to link a view to a model in vb.net code First

I've an old programm with edmx. Inside this one, I've linked a class (Table) To a View (Table/filter on a value of a column)
I want migrate this project to code first.
I copy/paste the project delete edmx file and generate models from an existing database.
All is good except this link.
<Table("JoinAffectation")>
partial public Class JointAffectation
public property Id as Long
public IdRecherche as Integer 'the link with my view
<NotMapped>
<ForeignKey("Id")>
PUBLIC OVERRIDABLE PROperty RechercheJoint as ViewRechercheJoint
But When I try to use function of automatical sort/filter using expression
I've error : The specified type member 'RechercheJoint' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
If I removed I error saying I don't same comumn and property... Also , How Can I stipulate RechercheJoint is mapped on IdRecherche
thanks for your help
Finally Using modelbuilder, I can join my view and my table like in edmx
<Table("JointAffectation")>
Partial Public Class JointAffectation
Public Property Id As Long
Public Property IdTypeJoint As Long
Public Property IdRecherche As Integer
Public Overridable Property JointType As JointType
<ForeignKey("Id")>
Public Overridable Property RechercheJoint As ViewRechercheJoint
End Class
<Table("ViewRechercheJoint")>
Partial Public Class ViewRechercheJoint
<Key>
<DatabaseGenerated(DatabaseGeneratedOption.None)>
Public Property Id As Integer
<StringLength(50)>
Public Property Libelle As String
<ForeignKey("IdRecherche")>
Public Overridable Property JointAffectations As ICollection(Of JointAffectation)
End Class
modelBuilder.Entity(Of JointAffectation)() _
.HasRequired(Function(e) e.RechercheJoint) _
.WithMany(Function(e) e.JointAffectations) _
.HasForeignKey(Function(e) e.IdRecherche)

How to model a 1:M relationship in EF without using the dependent's primary key as the foreign key?

I have three entities A, B, and C. The property MarketAccountNumber on entity C needs to be accessible through entity A.
The entities are as follows:
Partial Public Class A
<Key>
<Column("CoID", Order:=0)>
Public Property CompanyId As Byte
<Key>
<Column("BNum", Order:=1)>
Public Property B_Number as Integer
Public Property ID as String
<ForeignKey("CompanyID, ID")>
Public Overridable Property B As B
End Class
Partial Public Class B
<Key>
<Column("CoID", Order:=0)>
Public Property CompanyId As Byte
<Key>
<Column("BNum", Order:=1)>
<StringLength(15)>
Public Property Code As String
End Class
Partial Public Class C
<Key>
Public Property C_Id as Integer
Public Property B_Code as String
Public Property MarketAccountNumber
End Class
The B_Code field on class C corresponds to Code on class B.
I would like to be able to modify class B as follows:
Partial Public Class B
<Key>
<Column("CoID", Order:=0)>
Public Property CompanyId As Byte
<Key>
<Column("BNum", Order:=1)>
<StringLength(15)>
Public Property Code As String
<ForeignKey(?????)>
Public Overridable Property C as ICollection(Of C)
End Class
Then I could write A.B.C.MarketAccountNumber to get the data, but I am not sure what to put for the foreign key in that relationship. I'm open to any suggestion that would allow me to achieve the goal.

In EF how do I code the class to access the foreign key?

EF 6, code first technique.
Two classes defined as:
Public Class SqlLayerTypeSet
Public Overridable Property SqlLayerTypeSetID As Integer
Public Overridable Property Name As String
Public Overridable Property Desc As String
Public Property ConferenceTypes As New List(Of SqlConferenceType)
End Class
Public Class SqlConferenceType
Public Property ID As Integer
Public Property Name As String
Public Property Desc As String
End Class
After seeding the tables look, respectively, as this:
What do I add to Class SqlConferenceType so I can access the existing foreign key SqlLayerTypeSet_SqlLayerTypeSetID which points back to the SqlLayerTypeSet that SqlConferenceType is a member of.
When I add whatever it is supposed to be, will that require a new migration?
I had thought that EF allows you to define properties in the class using a convention that simply gives you access to the foreign key but doesn't actually change the table definition. The way I have been trying to add a property to the class is actually adding another column in the table when all I really want to do is access the column that EF code first already created.
I know this is a basic question, but I just can't seem to find the right SO post that explains it to me.
Added after initial post:
This is the line I added that adds access to the parent:
Public Overridable Property SqlLayerTypeSet As SqlLayerTypeSet
But if I try to add a specific property for the parent's key such as:
Public Property SqlLayerTypeSetID as Integer
That creates the extra column. Is it the case that the only property I can add to Class SqlConferencetype is the navigation property, and I simple have to retrieve the foreign key value using navigation as opposed to being able to define a property that simply holds the foreign key value?
Public Class SqlLayerTypeSet
Public Overridable Property SqlLayerTypeSetID As Integer
Public Overridable Property Name As String
Public Overridable Property Desc As String
<ForeignKey("SqlConferenceType")>
Public Overridable Property SqlConferenceTypeID as Integer 'Foreign key property
Public Overridable Property ConferenceTypes As New List(Of SqlConferenceType) 'Relationship property
End Class
Public Class SqlConferenceType
Public Property ID As Integer
Public Property Name As String
Public Property Desc As String
Public Overridable Property SqlLayerTypeSet as SqlLayerTypeSet 'Relationship property
End Class

The navigation property is not a declared property on type. Verify that it has not been explicitly excluded from the model

Usually, for such cases there is a messup in the declaration of Foreign Keys but I have run my eyes over this code countless times.
Manifests and BL are parent-child entities.
Namespace models
Public Class manifest
<DatabaseGenerated(DatabaseGeneratedOption.None)>
<Key>
Public Property id As Integer 'uses SQL sequence and not autogenerated
Public Property arrivalDate As Date
Public Overridable Property BL As IEnumerable(Of bl)
Public Overridable Property Vessel As vessel
end Class
End Namespace
And also
Namespace models
Public Class bl
<DatabaseGenerated(DatabaseGeneratedOption.None)>
<Key> <Column(Order:=2)>
Public Property blid As Integer
<Key> <Column(Order:=1)>
<ForeignKey("manifest")>
Public Property manifestid As Integer
<ForeignKey("manifestid")>
Public Overridable Property manifest As manifest
<Required>
Public Overridable Property container As IEnumerable(Of container)
End Class
End Namespace
But in the end, the outcome is "The navigation property 'BL' is not a declared property on type 'manifest'. Verify that it has not been explicitly excluded from the model and that it is a valid navigation property."
Any hint on what am I missing?

Entity Framework Core - Audit

Is there a way to write an Audit log automatically?
I have created a DbSet(Of Protocols)
Here is my protocol class:
Public Class Protocol
Inherits ModelBase
Implements ILogicalTimestamp
<Key>
Public Property ProtocolId As Integer
<Required>
Public Property ProtocolText As String
Public Property CreatedByUserId As Integer?
<Required>
Public Property CreatedByUser As User
<Required>
<DefaultValue(0)>
Public Property Type As ProtocolType
Public Property LinkedToUserId As Integer?
Public Property LinkedToUser As User
Public Property LinkedToBusinessPartnerId As Integer?
Public Property LinkedToBusinessPartner As BusinessPartner
Public Property LinkedToClientId As Integer?
Public Property LinkedToClient As Client
Public Property LinkedToSettingId As Integer?
Public Property LinkedToSetting As Setting
Public Property LastUpdateTimestamp As Date? Implements ILogicalTimestamp.LastUpdateTimestamp
Public Property CreationTimestamp As Date? Implements ILogicalTimestamp.CreationTimestamp
Public Enum ProtocolType
AutoChanges = 0
Explicitly = 1
End Enum
End Class
How can i write changes in protocol?
And how can i get the current UserId into the SaveChanges method to fill CreatedByUserId property in my protocol class?
Maybe anyone has an idea to do that automatically.
You can create a custom DB Context inheriting from DbContext, and then override the SaveChanges() method, so you can manipulate the data before/after modification.
Or you can use a library like Audit.EntityFramework, or check its code (C# sorry).
Also the library EntityFramework-Plus can probably help.