Entity Framework 6 Casscade Deletes and DropForeignKey fails on auto generated constraint name - entity-framework

Entity Framework 6 Casscading Deletes and DropForeignKey fails on auto generated constraint name
I've been running into a bit of an issue with Entity Framework and cascade deletes between two tables on several one-to-many relationships.
Initially it looked like the correct path to take was to configure the table mappings with the OnModelCreating method of DbContext turning off cascade delete in a manner such as
modelBuilder.Entity<SourceTable>()
.HasOptional(x => x.NavigationProperty)
.WithOptionalDependent()
.WillCascadeOnDelete(false);
This however did not work throwing an exception stating
Cannot delete or update a parent row: a foreign key constraint fails...
More research lead me to believe that this is because all affected entities must be loaded into the context (eager fetched) so that entity framework may set the FK references to null as part of the transaction. This is not practical for my needs based on the size of the relational graph I'd be dealing with.
My next approach was to modify the Seed method of the Configuration class and run some arbitrary SQL to drop the Foreign Key constraint and re-add it as a ON DELETE SET NULL constaint. This worked in most cases, however one of the consraints has what appears to be an auto generated unpredicatable name that is diffrent on each call of Update-Database. Given that the name can't be predicted the ALTER statments aren't particualr helpful
context.Database.ExecuteSqlCommand(#"ALTER TABLE SourceTable DROP FOREIGN KEY FK_9405957d032142c3a1227821a9ed1fdf;
ALTER TABLE SourceTable
ADD CONSTRAINT FK_ReasonableName
FOREIGN KEY (NavigationProperty_Id) REFERENCES NavigationProperty (Id) ON DELETE SET NULL;");
Finally, I've taken the apprach to use the migration functionality (DbMigration) and override Up method and leveraging the DropForeignKey method along side more explicit SQL to re-add the constraint (EF does not appear to provide a factility to create a ON DELETE SET NULL constraint).
DropForeignKey("SourceTable", "NavigationProperty_Id", "DestinationTable");
Sql("ALTER TABLE SourceTable ADD CONSTRAINT FK_ReasonableName FOREIGN KEY (NavigationProperty_Id) REFERENCES DestinationTable (Id) ON DELETE SET NULL;");
This works great, up until I encounter the constraint with the auto generate name. At this point the DropForeignKey method fails with an exception that is swallowed up by
System.Runtime.Serialization.SerializationException: Type is not resolved for member 'MySql.Data.MySqlClient.MySqlException,MySql.Data...
When dumping the migration to a SQL script file it becomes clear that the DropForeignKey simply generates a FK with a more predictable, non-ambiguous byte stream array.
Is there a proper EF Code First approach to solve the problem of setting FK column values to null when deleting the refrenced row, or am I stuck having to hand code SQL in order to gain this functionality?

Related

How to enable cascading delete in Edmx Designer on many to many relation

I am using VS2012 and the Entity designer to generate both the database and the models. I have a very basic scenario of Table1 to Table1and2JoinTable to Table2. Something like Students, Classes, StudentClasses. You can have many students in many classes. I would like to have a cascading delete. So if you delete a student any rows in the StudentClass join table are deleted for that student id. Same for deleting a class any rows in the StudentClass are deleted for that class id. After setting up the many to many association in the designer and setting the cascade delete options you get the following error when you attempt to generate the database:
Error 132: End 'Student' on relationship 'Model1.StudentClass' cannot have operation specified since its multiplicity is ''. Operations cannot be specified on ends with multiplicity ''.
Here is a small example:
Here is the association created:
And the resulting error messages:
Here is a portion of the SQL code for generating the database tables:
-- Creating foreign key on [Students_Id] in table 'StudentClass'
ALTER TABLE [dbo].[StudentClass]
ADD CONSTRAINT [FK_StudentClass_Student]
FOREIGN KEY ([Students_Id])
REFERENCES [dbo].[Students]
([Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- This should be ON DELETE CASCADE ON UPDATE NO ACTION;
GO
-- Creating foreign key on [Classes_Id] in table 'StudentClass'
ALTER TABLE [dbo].[StudentClass]
ADD CONSTRAINT [FK_StudentClass_Class]
FOREIGN KEY ([Classes_Id])
REFERENCES [dbo].[Classes]
([Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- This should be ON DELETE CASCADE ON UPDATE NO ACTION;
GO
I know how to work around this by just editing the database script and add in the on delete cascade option. But, I don't want to do this because I am going to come back to the designer many times as the project grows and I don't want to have to remember this step every time.
Has anyone figured out how to resolve this?
It seems to be an edmx restriction, which I don't really understand. Code-first is perfectly capable of generating a junction table with two cascading ON DELETE constraints, but model-first and database-first do not allow the same configuration in the edmx. Normally, cascade actions are configured on the 'one' end of an association. Maybe it is too complex to check the validity of cascade actions on '*' ends (only when both ends are '*').
For the cascaded delete to happen with a context based on an edmx model, you have to load a parent and its children and then delete the parent.
var cls = db.Classes.Include(c => c.Students).Single(c => c.Id = 1);
db.Classes.Remove(cls);
db.SaveChanges();
The executed SQL statements show that the Class is fetched from the database in a JOIN statement with Student. Then the StudentClasss and the Class are deleted respectively.
Obviously, this is much more expensive than enabling cascaded delete in the database.
The work-around to modify the DDL each time after is was generated is not attractive, of course. But I think the only alternative is to make StudentClass part of the model and configure cascaded delete on the 'one' ends of the new associations. Or go code-first.
First of all make sure that you have an ON DELETE CASCADE specified in your Foreign Keys on database side.
I had similar problem and just adding ON DELETE CASCADE solve it instead of setting End1OnDelete and End2OnDelete properties.

Entity framework and table without primarykey and notnull value

I use entity framework in mvc razor.
edmx does not accept a table with all allow nulls columns.
When i update model from database the table is not getting added in entity framework.
USE [exampledb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Table_1](
[id] [int] NULL,
[name] [varchar](50) NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
Well, Entity Framework needs a way for unique identification of each row in your table. Since in db design row identification is done through primary key (Entity Key in model), you need to add them to your table, otherwise you will have problems with adding your table to EF model. Sometimes entity can infer entity key automatically (for example, it often happens when you generating model from view). Also, for view, common way to overcome this problem is to use ISNULL statement.
But for table - you must have non-nullable identification field, better - primary key (to conform to db design patterns), in order this table to be added to your model.

EF many to many with junction entity database first

I have a junction table with and idenity primary key columns to realize a many to many relationship. Visual Studio automatically detects it as a many to many relationship and the junction table is not an entity.
How can i realize it that also this table is generated as an entity? I need this for breeze.js .
You just need to add additional columns (or properties) to that table (or model).
You said that your table has acolumn named ID and it's the primary key withe IsIdentity set to true. It must works, I'm using this approach...
There must be a problem or missing with your table definition. However, if all are OK, just add a nullable column in your table and update your model from database. The problem will go away.

Violation of PRIMARY KEY constraint on linked record when add a record using the entity framework

I have a table called farmers. Each farmer has a country specified that is mandatory.
When I add a new farmer to the database using antity framework, I get a violation on the country table. It looks like the entity framework wants to add the country to the country table, but I only want the guid in my farmer table:
Violation of PRIMARY KEY constraint 'PK_Country'. Cannot insert
duplicate key in object 'dbo.Country'. The statement has been
terminated.
Can somebody advise me on what I'm doing wrong? here the code for the insert:
newFarmer.Guid = Guid.NewGuid();
ents.Farmer.AddObject(newFarmer);
ents.SaveChanges();
return newFarmer;
I even checked the state of the country and it says unchanged.
One possible solution is that Entity Framework doesn't understand that your entity primary key is also the identity and should be auto-incremented. I had the same problem in an application using EF 4.1 with database first. To solve the problem, I had to::
Make sure my entities primary key had a name "ID" (to avoid putting a decorator [Key] above my Model class.
Make sure the property option "Identity" of your database system (SQL Server in my case) is set to "Yes".
Then, my EF4.1 was able to do the insert and update of my entities.
Hope this helps!

How to handle "secondary" keys in Entity Framework

I'm evaluating using EF against an existing schema - the problem is that I can't work out how to set up associations between tables where the foreign key is NOT the primary key of the master table.
As an example, a foo may have many bars as defined like this (forgive the pseudocode):
table foo {
int foo\_id pk,
char(10) foo\_code,
...
}
table foobar {
int bar\_id pk,
char(10) bar\_foo\_code fk(foo.foo\_code),
...
}
What am I missing to be able to create the foo_foobar association, and hence a Bars navigation property on the Foo entity?
Linq to entities doesn't support Foreign Keys which don't point to the primary key of a table (see log message 3). Linq to entities will treat it as a normal field on a table. You won't be able to navigate to the entity it's linked to.
If you have an existing schema i'd recommend using the edm generator as this will create the EMDX file, code behind and even the view code (which can be very large). If your existing scheme is quite large Check out this post, which explains how to deal with large schemas.
When you run the EDM Generator you'll find out all the things that are not supported.
Looking at a previous EDMGen2.exe log we got the following types of messages back:
The data type 'sql_variant' is not
supported, the column 'ColumnName'
in table 'TableName' was
excluded.
The table/view 'tableName' does not
have a primary key defined. The key
has been inferred and the definition
was created as a read-only table/view
The relationship 'RelationshipName'
has columns that are not part of
the key of the table on the
primary side of the relationship
which is not supported, the
relationship was excluded.
We've also found that the Linq project actually crashed Visual Studio quite alot as the code file produced by EDM was well over 80 mb.