In the RC1 of EntityFramework 7, released yesterday, Cascade Delete was added.
To disable it per relationship, I can use :
builder.Entity<Site>().HasOne(e => e.Person)
.WithMany(x => x.Sites).Metadata.DeleteBehavior = DeleteBehavior.Restrict;
I want to disable it globally for a DbContext, but I didn't find a way. How can I do ?
Someone stated on the github project forum that the only way to do it right now is to iterate through all relationships in the method OnModelCreating(ModelBuilder builder), and set the DeleteBehavior property to DeleteBehavior.Restrict :
foreach (var relationship in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
Right now conventions are not configurable. The current CascadeDelete convention only applies to required relationships. Relationships Conventions: Cascade Delete on efproject.net (Official EF7 docs) You could disable the required relationship explicitly if you understand well the consequences.
modelBuilder.Entity<Site>()
.HasOne(p => p.Person)
.WithMany(b => b.Sites)
.IsRequired(false);
Otherwise (and recommended), you need to set the On Delete behavior explicitly ( as you already discovered).
modelBuilder.Entity<Site>()
.HasOne(p => p.Person)
.WithMany(b => b.Sites)
.OnDelete(DeleteBehavior.Restrict);
Related
I have a foreign key field that is generated by Entity Framework (6) at runtime. This field is related to a interfaces T field. So we end up with a field called InterfaceFieldName_Id - I would like to rename this (prefereably via the Fluent API) to TypeFieldName_Id. I know how I can do this by adding in FK Id field to the POCO class, but I would prefer not to do that.
Is there a way to rename this generated field name?
You can use Map method to rename a Foreign Key that is not defined in the Model:
modelBuilder.Entity<Entity1>()
.HasRequired(c => c.Entity2NavProperty)
.WithMany(t => t.Entity1NavigationProperty)
.Map(m => m.MapKey("TypeFieldName_Id"));
If you already have a property in your model that represent the FK and it was renamed by EF in your DB, then you should check your relationship.Code First falls back to automatically introducing one in the database in case the foreign key property hasn't been discovered by convention, and none is configured. The foreign key property will be discovered by convention if it is named [Target Type Key Name], [Target Type Name] + [Target Type Key Name], or [Navigation Property Name] + [Target Type Key Name].
Now to configure explicitly what is the FK property you want to use, you can can do the following:
modelBuilder.Entity<Entity1>()
.HasRequired(c => c.Entity2NavProperty)
.WithMany(t => t.Entity1NavigationProperty)
.HasForeignKey(d => d.TypeFieldName);
And if you want to use a different name for TypeFieldName in your DB, then you can also do this:
modelBuilder.Entity<Entity1>().Property(d=>d.TypeFieldName).HasColumnName("TypeFieldName_Id")
You can specify the column name fluently:
modelBuilder.Entity<YourEntity>()
.HasRequired(c => c.InterfaceFieldName)
.WithMany(d => d.YourColumnName)
.HasForeignKey(c => c.FieldName);
If you all need more details I will send them for sure. Here is a screen shot containing 2 tables:
Basically this is what looks like in SQL today:
I am trying to use the fluent API for the relationship but not sure how to do it.
Table 1 has a PK and a FK.
Table 2 does not have a PK, only FK.
Below is an example of what I need but this code applies to a different set of tables. I am trying to get the "relationship" syntax correct for the scenario described here:
this.ToTable("Server");
//primary key
this.HasKey(t => t.serverId);
//properties
...
//relationships
this.HasMany(n => n.NetworkAdapters)
.WithRequired(s => s.Server)
.HasForeignKey(s => s.serverId)
.WillCascadeOnDelete(true);
Thank you
Without the primary key on table 2 you are most likely looking for a One-to–Zero-or-One relationship. You might possibly be requiring both ends which I will describe too.
One-to–Zero-or-One
// Configure the primary key for Table1
modelBuilder.Entity<Table1>()
.HasKey(t => t.networkAdapterId);
// Map one-to-zero or one relationship
modelBuilder.Entity<Table2>()
.HasRequired(t => t.Table1)
.WithOptional(t => t.Table2);
One-to-One
// Configure the primary key for the Table1
modelBuilder.Entity<Table1>()
.HasKey(t => t.networkAdapterId);
// Map one-to-one relationship
modelBuilder.Entity<Table2>()
.HasRequired(t => t.Table1)
.WithRequiredPrincipal(t => t.Table2);
See here for more details
When I create two entities with many to many relationship, it will generate a relationship table in the database, is it possible to specify the table's name?
Yes but you have to use fluent API:
mb.Entity<FirstEntity>()
.HasMany(a => a.SecondEntities)
.WithMany(b => b.FirstEntities)
.Map(mc =>
{
mc.ToTable("YourTableName", "YourDbSchema");
mc.MapLeftKey("FirstEntityKeyColumnName");
mc.MapRightKey("SecondEntityKeyColumnName");
});
I'm developing an application in Zend Framework to handle the rentals for a commercial property rental company. The company has multiple buildings which each have multiple floors, which each have multiple units.
The models I've setup just extend Zend_Db_Table_Abstract, and I've set them up with $_dependentTables and $_referenceMaps with cascading delete, such that when I delete a floor, all the units within it are deleted too, and when I delete a building, all the floors in it are deleted. However, when I delete a building and the floors are deleted, the delete is not cascaded through to each floor's units. (edit: I'm using MySQL, so I am not able to use referencial integrity at the db level.)
I've looked at how the deletes are cascaded, and it appears they aren't cascading because the cacaded deletes are executed using a Zend_Db_Table object, not a Zend_Db_Table_Row object (which you have to use to achieve cascading).
Is there any way I can update the system so that the delete cascades all the way down? Is there a way I can modify the relationships of my classes, or would I need to use something like Doctrine?
(I guess I could override the delete() method for the row of each table or something, but I just wondered if this is possible using the relationships functionality of ZF?)
If it helps, here's the relevant parts of the class definitions:
class Buildings extends Zend_Db_Table
{
protected $_dependentTables = array('Floors');
}
class Floors extends Zend_Db_Table
{
protected $_dependentTables = array('Units');
protected $_referenceMap = array(
'Building' => array(
'columns' => 'building_id',
'refTableClass' => 'Buildings',
'refColumns' => 'id',
'onDelete' => self::CASCADE,
));
}
class Units extends Zend_Db_Table
{
protected $_referenceMap = array(
'Floor' => array(
'columns' => 'floor_id',
'refTableClass' => 'Floors',
'refColumns' => 'id',
'onDelete' => self::CASCADE,
));
}
Just to be sure... Are you using a RDBMS that doesn't support referencial integrity?
For my taste, it's easier (and more portable, in case you decide to access the DB from another application in the future) to declare the ON DELETE CASCADE in your RDBMS (provided that it allows it), instead of emulating it with the framework.
It seems that the Zend Framework documentation also advices in this sense:
http://framework.zend.com/manual/en/zend.db.table.relationships.html#zend.db.table.relationships.cascading
In my code I have a many to many relationship defined using:
modelBuilder.Entity<Post>()
.HasMany( p => p.Authors ).WithMany();
Post.Authors is an ICollection of User entities.
The ModelBuilder automatically creates a table called PostUsers.
How can I override the table naming convention so that the ModelBuilder names the table PostAuthors when the database is created from the model?
Thanks!
You can use:
modelBuilder.Entity<Post>
.HasMany(p => p.Authors)
.WithMany()
.Map(m => m.ToTable("PostAuthors", "dbo"));