简体   繁体   中英

How to create multiple foreign keys from one table to another if table1 contains multiple fields with fk to the same column of table2

I have "info" table with some fields that point to "id" column of "file_uploads" table. Also I third table with fk to "file_uploads", lets call it "another_table". How can I describe relationships in EF fluent api to use Linq Join or Include Queries?

InfoRecord {
    public long Id {get; set;}
    public long File1Id {get; set;}
    public long File2Id {get; set;}
    public long File3Id {get; set;}

    public List<FileUploadRecord> Files {get; set;}
}

FileUploadRecord {
    public long Id {get; set;}
    public long Url {get; set;}

    public InfoRecord Info {get; set;}
}

AnotherTableRecord {
    public long Id {get; set;}
    public long ImageId {get; set;}

    public long FileUploadRecord Image { get; set; }
}

I know that I can create simple raw sql query with join and it will work, but It doesn't work with Linq .Include or .Join. I've tried to solve it by different ways, bu EF throw errors about bad FK relations.

I think you need to tweak your models a little bit. Right now, the InfoRecord table has three columns pointing to the files table. The problem with that is: What if tomorrow you need to support more files? Adding more columns is not optimal. The process of fixing this is what's called Database Normalization .

If InfoRecord needs "several columns to point to an id" on FileUpload , you have a one-to-many relationship - One InfoRecord can have one or more files. We can achieve normalization using 3 tables:

1 - FileUpload (the actual files, most basic entity. No relationships here.)

public class FileUpload
{
    public long Id { get; set; }

    public string FileName { get; set; }

    public string FilePath { get; set; }
}

2 - InfoRecord - As your question, a InfoRecord can have many files:

public class InfoRecord
{
    public long Id { get; set; }

    public string Title { get; set; }

    public ICollection<FileUploadRecord> Files { get; set; }
}

And lastly, the entity that "glues" them together:

3 - FileUploadRecord - It has an FK to FileUpload and to InfoRecord

public class FileUploadRecord
{
    public long Id { get; set; }

    // FK to InfoRecord. Usefull for update scenarious
    // without having to load the whole entity.
    public long InfoRecordId { get; set; }

    public InfoRecord InfoRecord { get; set; }

    // FK To the actual file upload
    public long FileId { get; set; }

    public FileUpload FileUpload { get; set; }
}

Then you can configure it using the FluentAPI like this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Configure the Entity that "glues" InfoRecord and FileUploads. 
    // One InfoRecord can have many files, so we need a table to store that relationship.
    modelBuilder.Entity<FileUploadRecord>()
        .HasOne(s => s.InfoRecord)
        .WithMany(g => g.Files)
        .HasForeignKey(s => s.InfoRecordId);

    modelBuilder.Entity<FileUploadRecord>()
        .HasOne(p => p.FileUpload)
        .WithMany()
        .HasForeignKey(p => p.FileId);
}

And to query using .Include like you wanted is easy now. The query below loads all InfoRecords with each respective files.

var recordsWithFiles = context.InfoRecords
                    .Include(p => p.Files)
                    .ThenInclude(p => p.FileUpload);

This is how the DB schema will look like: 在此输入图像描述

As per the "another_table", looks like it's a simple one-to-one relationship so, you can just use plain EF Core Conventions for it. Of course .Include also works here.

public class AnotherTableRecord
{
    public long Id { get; set; }

    // FK To the actual file upload
    public long ImageId { get; set; }

    public FileUpload Image { get; set; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM