Reputation: 111
In my model I'm using bigint (ulong) as the type for entity keys. The value 0 must be used for empty keys. Columns for foreign keys must not be nullable, because in my methods I only want to check for the value 0 and not for null. Everything works fine, except for the deletion of related entities that are referenced by other entities.
Here is my model:
<cf:entity name="Customer" cfom:bindingList="false">
<!--persistenceIdentity is true, because the corresponding column for this property must be auto incremented by the database.-->
<cf:property name="Id" typeName="ulong" key="true" persistenceIdentity="true" cfps:hint="CLUSTERED" />
<cf:property name="Name" typeName="string" />
</cf:entity>
<cf:entity name="Order" cfom:bindingList="false">
<!--persistenceIdentity is true, because the corresponding column for this property must be auto incremented by the database.-->
<cf:property name="Id" typeName="ulong" key="true" persistenceIdentity="true" cfps:hint="CLUSTERED" />
<!--persistenceNullable is false, because the column for the foreign key must not be nullable.-->
<cf:property name="Customer" typeName="{0}.Customer" persistenceNullable="false" />
</cf:entity>
Here is my code:
Customer customer = new Customer();
customer.Save();
Order order = new Order();
order.Customer = customer;
order.Save();
customer.Delete();
The last statement gives the following error: Cannot insert the value NULL into column 'Order_Customer_Id', table 'CodeFluentTest.dbo.Order'; column does not allow nulls. UPDATE fails.
This is because the Customer_Delete stored procedure contains the following update statement: UPDATE [Order] SET [Order].[Order_Customer_Id] = NULL WHERE ([Order].[Order_Customer_Id] = @Customer_Id)
Of course this will not work, because the Order_Customer_Id column is not nullable. How can I instruct CodeFluent to put the value 0 instead of NULL into the Order_Customer_Id column?
Upvotes: 0
Views: 52
Reputation: 139075
CodeFluent does not really support object keys that are not nullable, because the implied semantics would be somehow strange. When you delete an object, from an OO perspective, the object is now null, it's identifier does not exist any more, it's not set to a specific 0 or other value. You will probably run into other problems with tweaking the model like this.
That being said, one way to change this behavior is to use the "persistenceUnlink
" attribute on the property involved, directly in the XML file. Unfortunately the graphical modeler does not support this (ancient) attribute and will override it everytime you modify the model and save it back using the GUI.
So, what you can do is use a custom aspect to automatically apply this attribute on properties where you want it. Here is a sample code for such an aspect (note the aspect runs on startup because it's really based on XML, not on the in-memory model contrary to most aspects):
<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1" defaultNamespace="unlink">
<cf:pattern name="Unlink Aspect" namespaceUri="http://www.example.com/unlink" preferredPrefix="ul" step="Start">
<cf:message class="_doc">
Sample aspect that removes auto unlink in delete procedures
</cf:message>
<cf:descriptor name="unlink" targets="Property" defaultValue="true" displayName="Unlink" typeName="boolean" description="Determines if this property will be unlinked during delete" category="Unlink Aspect" />
</cf:pattern>
<?code @namespace name="System" ?>
<?code @namespace name="System.Xml" ?>
<?code @namespace name="CodeFluent.Model" ?>
<?code
// use a special utility method to get all elements
// with the given attribute in a given namespace URI
var properties = Project.Package.RootModelPart.SelectElements("unlink", "http://www.example.com/unlink", false);
foreach(var property in properties)
{
// here we set a special attribute not supported by the GUI designer in Visual Studio
property.SetAttribute("persistenceUnlink", "false");
}
?>
</cf:project>
What you must do is:
Upvotes: 1