Entity Framework Core Nullable FK not getting records - entity-framework-core

I have an OrderHeader table and OrderLines table. I also have a Rate table. Both OrderHeader and OrderLines can have rates. So this Rate table is setup as:
RateId
RateValue
OrderHeaderId
OrderLineId
So if we're adding header rates the OrderHeaderId is filled in and OrderLineId is null. When adding line rates the opposite happens.
My OnModelCreating() has:
modelBuilder.Entity<Rate>(entity =>
{
entity.HasOne(d => d.OrderHeader)
.WithMany(p => p.Rates)
.HasForeignKey(d => d.OrderHeaderId)
.HasContraintName("FK1")
.IsRequired(false);
entity.HasOne(d => d.OrderLines)
.WithMany(p => p.Rates)
.HasForeignKey(d => d. OrderLineId)
.HasContraintName("FK2")
.IsRequired(false);
}
When I query for a OrderLine record the Rates has 0 records in it, but in the DB there are 2 records for this OrderLineId.
I'm not really sure what else I should be looking for. I thought the .IsRequired(false) would have fixed the issue since in Rates table those FK's can have null values but it didn't.

Related rows are only loaded if you request them, otherwise querying a single entity instance might load your whole database into memory. Read EF Core Loading Related Data
Also the FK between Rate and OrderLines should be on (OrderHeaderId,OrderLineId) to ensure that the Rate's OrderLines all belong to the Rate's OrderHeader. And for similar reasons the primary key of OrderLines should also be (OrderHeaderId,OrderLineId).

Related

Need some advice for a Many to many fluent code problem

Hi I got 2 Many to Many table linked with a joint table.
UsagerEW <-> UsagerPermissionEW <-> Permission
This is an old DB and the UsagerEW do not have a Id column but a CodeInt instead.
When I scaffold this database, EF7 create the 3 tables and relations between all. But do not skip the join table to create a "pure" many to many relationships.
So I add 2 virtual properties in each table:
In permission: public virtual ICollection UsagerEWs { get; } = new HashSet();
In UsagerEW: public virtual ICollection Permissions { get; } = new HashSet();
Then I add this fluent code to create a Many2Many relationship:
modelBuilder.Entity<PermissionUsagerEW>().HasKey(k => k.id);
modelBuilder.Entity<UsagerEW>()
.HasMany(u => u.Permissions)
.WithMany(p => p.UsagerEWs)
.UsingEntity<PermissionUsagerEW>(
p => p.HasOne(e => e.permission)
.WithMany()
.HasForeignKey(e => e.permissionId),
p => p.HasOne(p => p.usagerEWcode_intNavigation)
.WithMany()
.HasForeignKey(e => e.usagerEWcode_int)
);
That code works great. I can read UsagerEW with permission directly. The only time this code failed is when I try to add permission to a UsagerEW.
I try to do: context.usagerEW.Permissions.add(new permission)
Or I try to create the UsagerPermission joint object and update the middle table directly. In the 2 case, I got this error:
The column name 'permissionId' is specified more than once in the SET clause or column list of an INSERT.
And to SQL code generated is
SET NOCOUNT ON;
INSERT INTO [PermissionUsagerEW] ([Permissionid], [UsagerEWcode_int], [permissionId], [usagerEWcode_int])
VALUES (#p0, #p1, #p2, #p3);
SELECT [id]
FROM [PermissionUsagerEW]
WHERE ##ROWCOUNT = 1 AND [id] = scope_identity();
So something is wrong with my fluent code.
Any idea??

How to declare cascade delete in EF when child table isn't mapped as separate entity

I have got a database first approach with EF5 and here is a fragment of mappings:
internal class xxxMapping : EntityTypeConfiguration<Order>
{
public xxxMapping ()
{
ToTable("my_table");
//......
HasMany(it => it.Documents)
.WithMany()
.Map(
m =>
{
m.ToTable("dependent_table");
m.MapLeftKey("left_key_id");
m.MapRightKey("right_key_id");
});
}
What is the best way to declare, using fluent API, that when some row is deleted from my_table, then dependent rows from dependent_table will be deleted too (Cascade delete option in FK)
UPD It seems to be working without any additional code (Of course - if foreign key in table is configured properly). But i'm not sure it's a good practice to do so

Need proper syntax using EF6 Fluent API between 2 tables using PK and FK

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

EF Doesn't Delete Records For Fluent API - Many To Many Relationship

I have 2 entities,
News
FileAttachment
I wanted to configure using code-first fluent API so that Each News can have 0,1 or more than 1 attachments.
here is what i'm using right now
public NewsMap()
{
this.ToTable("News"); // Table Name
this.HasKey(m => m.Id); // Primary Key
// Field Definition
this.Property(m => m.Title).HasMaxLength(255).IsRequired();
this.Property(m => m.Body).HasColumnType("Text").IsRequired();
this.Property(m => m.Summary).HasMaxLength(1000).IsRequired();
this.Property(m => m.AuthorId).IsRequired();
this.Property(m => m.CreatedOn).IsRequired();
this.Property(m => m.UpdatedOn).IsRequired();
this.HasMany(m => m.Attachments).WithMany().Map(m => m.MapLeftKey("NewsId").MapRightKey("AttachmentId"));
}
public class FileAttachmentMap : EntityTypeConfiguration<FileAttachment>
{
public FileAttachmentMap()
{
this.ToTable("FileAttachments"); // Table Name
this.HasKey(m => m.Id); // Primary Key
// Field Definition
this.Property(m => m.DisplayName).HasMaxLength(256).IsRequired();
this.Property(m => m.PhysicalFileName).HasMaxLength(256).IsRequired();
this.Property(m => m.Extension).HasMaxLength(50).IsRequired();
this.Property(m => m.IsImage).IsRequired();
this.Property(m => m.ThumbTiny).HasMaxLength(275).IsOptional();
this.Property(m => m.ThumbSmall).HasMaxLength(275).IsOptional();
this.Property(m => m.ThumbMid).HasMaxLength(275).IsOptional();
this.Property(m => m.ByteSize).IsRequired();
this.Property(m => m.StorageType).IsRequired();
this.Property(m => m.CreatedOn).IsRequired();
this.Property(m => m.UpdatedOn).IsRequired();
}
}
This mapping correctly generates an intermediate table named NewsFileAttachment with two fields :
NewsId
AttachmentId
On News Entity when i call News.Attachments.Add(Attachment); it correctly adds records in both Attachment & NewsAttachment tables.
When i remove some list item from News.Attachments it correctly removes record from NewsAttachment table, but it doesn't delete record in FileAttachment table. I wanted to remove that too.
Can someone please suggest a better Fluent API configuration to achieve this?
Thanks,
Amit
EDIT
In my case FileAttachment stores files for various purpose. i've Blog entity that too have attachments. So, two intermediate tables BlogAttachments & FileAttachments. Now if i use WithOptional as (I can't use WithRequired as i need BlogId & NewsId both in FileAttachment table), i can get rid off intermediate table, but still delete doesn't delete record from FileAttachment table, it just make NewsId/BlogId NULL.
Any suggestion? Main thing is I do not wanted to create separate tables with all the fields i have in FileAttachment table.
That's expected - as it creates many-to-many and extra table - the cascade only applies to that table.
There is no direct 'FK' relationship in between your News and
Attachment, as it goes through a join table. And thus you cannot expect for e.g. attachment to be deleted, if the news does - as attachment could have other news relating to it.
See also this one - it's somewhat relevant.
One to Many Relationship with Join Table using EF Code First
i.e. if your structure permits don't explicitly create many-to-many (don't put collection on both sides, or similar in fluent config).
In your case providing your 'attachments' are not reusable in between News - then just put a collection navigation property in the News - and leave attachment w/o any - or make a 'FK', single instance navigation from Attachment (like a 'Parent') if you need it.
On the other side, if an attach... could be parented by different
news records - then you shouldn't have cascade delete anyways.
note: check your generated migration script - or SQL/Db - to see exactly what it creates - and make sure there is no intermediate table created - and only one 'FK' going from 'attachment' to 'news'.
edit:
modelBuilder.Entity<News>()
.HasMany(c => c.Attachments)
.WithOptional() // or WithRequired (test to see which is better for you)
.WillCascadeOnDelete(true);
...and make one public ICollection<FileAttachment> Attachments {get;set;} in the News.
(actually the collection property is all you need - but configuration is to be safe you get what you want)
That'd make you 1-to-many (or many-to-one), which is the nature of your data (as you said in comments) - and you can have cascade deletes.

How to specify relationship name in code-first many to many relationship

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");
});