Search code examples
codefluent

Default persistence enforce set to true would anyway delete association table's lines


The property defaultPersistenceEnforce is set to true at project level. We consider following example.

Meeting ----*> Contact <---- Case

When we have one contact referenced in the table Case, the call of stored procedure Contact_Delete() would fail as exepected.

But when there's no reference in table Case the execution of stored procedure Contact_Delete() would delete the lines inside association table Meeting_Contacts_Contact.

It doesn't make much sense since I would like to prevent such behavior. In particular, I didn't specify any cascade relationship for deletion.

I would like to make sure that tuples are not being erased in such tables, in particular when there are referenced. How can I have the stored procedure Contact_Delete() to only delete Contact and don't consider references ?

Thanks for your answer,

Enclosed the model part and the definition of Contact_Delete stored procedure.

<cf:project defaultNamespace="WcfServices.Model" xmlns:cf="http://www.softfluent.com/codefluent/2005/1" xmlns:cfx="http://www.softfluent.com/codefluent/modeler/2008/1" xmlns:cfps="http://www.softfluent.com/codefluent/producers.sqlserver/2005/1" xmlns:cfom="http://www.softfluent.com/codefluent/producers.model/2005/1" xmlns:cfsps="http://www.softfluent.com/codefluent/producers.sqlpivotscript/2013/1" defaultPersistenceEnforce="true" createDefaultMethodForms="true" createDefaultApplication="false" createDefaultHints="false">
  <cf:import path="Default.Surface.cfp" />
  <cf:producer name="SQL Server" typeName="CodeFluent.Producers.SqlServer.SqlServerProducer, CodeFluent.Producers.SqlServer">
    <cf:configuration produceViews="true" targetDirectory="..\WcfServices.persistence" cfx:targetProject="..\WcfServices.persistence\WcfServices.persistence.sqlproj" cfx:targetProjectLayout="Update, DontRemove" />
  </cf:producer>
  <cf:producer name="Business Object Model (BOM)" typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom">
    <cf:configuration compileWithVisualStudio="true" compile="false" codeDomProviderTypeName="CSharp" targetDirectory="..\WcfServices.model" cfx:targetProject="..\WcfServices.model\WcfServices.model.csproj" cfx:targetProjectLayout="Update">
      <subProducer typeName="Ixcys.Producers.ServiceModelProducer.ServiceProducer, Ixcys.Producers.ServiceModelProducer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" compileWithVisualStudio="true" compile="false" codeDomProviderTypeName="CSharp" targetDirectory="..\WcfServices.proxy" silverlightTargetVersion="Unspecified" jsonOptions="EnableJson" cfx:targetProject="..\WcfServices.web\WcfServices.web.csproj" cfx:targetProjectLayout="Update" />
    </cf:configuration>
  </cf:producer>
  <cf:producer name="SQL Server Pivot Script" typeName="CodeFluent.Producers.SqlServer.SqlPivotScriptProducer, CodeFluent.Producers.SqlServer">
    <cf:configuration targetDirectory="..\WcfServices.web" cfx:targetProject="..\WcfServices.web\WcfServices.web.csproj" cfx:targetProjectLayout="Update" />
  </cf:producer>
  <cf:entity name="Contact" namespace="Example.Model.Contact" categoryPath="/WcfServices.Model">
    <cf:property name="ContactId" key="true" persistenceEnforce="true" />
    <cf:property name="Name" persistenceEnforce="true" />
  </cf:entity>
  <cf:entity name="Case" namespace="Example.Model.Contact" categoryPath="/WcfServices.Model">
    <cf:property name="CaseId" key="true" persistenceEnforce="true" />
    <cf:property name="Description" persistenceEnforce="true" />
    <cf:property name="InChargeContact" typeName="Example.Model.Contact.Contact" persistenceEnforce="true" />
  </cf:entity>
  <cf:entity name="Meeting" namespace="Example.Model.Contact" categoryPath="/WcfServices.Model">
    <cf:property name="MeetingId" key="true" persistenceEnforce="true" />
    <cf:property name="Date" typeName="date" persistenceEnforce="true" />
    <cf:property name="Label" persistenceEnforce="true" />
    <cf:property name="Contacts" typeName="Example.Model.Contact.ContactCollection" persistenceEnforce="true" />
  </cf:entity>
</cf:project>

The stored procedure Contact_Delete

CREATE PROCEDURE [dbo].[Contact_Delete]
(
 @Contact_ContactId [uniqueidentifier],
 @_rowVersion [rowversion]
)
AS
SET NOCOUNT ON
DECLARE @error int, @rowcount int
DECLARE @tran bit; SELECT @tran = 0
IF @@TRANCOUNT = 0
BEGIN
 SELECT @tran = 1
 BEGIN TRANSACTION
END
DELETE FROM [Meeting_Contacts_Contact]
    WHERE ([Meeting_Contacts_Contact].[Contact_ContactId] = @Contact_ContactId)
SELECT @error = @@ERROR, @rowcount = @@ROWCOUNT
DELETE FROM [Contact]
    WHERE (([Contact].[Contact_ContactId] = @Contact_ContactId) AND ([Contact].[_rowVersion] = @_rowVersion))
SELECT @error = @@ERROR, @rowcount = @@ROWCOUNT
IF(@rowcount = 0)
BEGIN
    IF @tran = 1 ROLLBACK TRANSACTION
    RAISERROR (50001, 16, 1, 'Contact_Delete')
    RETURN
END
IF @tran = 1 COMMIT TRANSACTION

RETURN
GO

Solution

  • This is by design. The delete procedure generated for an entity also deletes the records of the many to many table.

    A simple workaround is to create a CFQL method DeleteById:

    DELETE(Id) WHERE Id = @Id
    

    This method generates the following stored procedure:

    CREATE PROCEDURE [dbo].[Meeting_DeleteById]
    (
     @Id [uniqueidentifier]
    )
    AS
    SET NOCOUNT ON
    DECLARE @deletedcount int
    DELETE FROM [Meeting]
        WHERE ([Meeting].[Meeting_Id] = @Id)
    SELECT @deletedcount = @@ROWCOUNT
    
    SELECT @deletedcount 
    RETURN
    GO