C
C#3mo ago
PixxelKick

Define a Many to Many navigation in EF Core without any Join Table

Restrictions 1. The model is Db First 2. I cannot modify the Db Schema (Im not in charge of it) Challenge Currently speaking I have a pseudo "Many to Many" relationship between 2 tables via a non unique column they both share and I LEFT JOIN on it. It looks something like so:
[PrimaryKey(nameof(A_Id), nameof(A_Version))]
public class DataModelA
{
public int A_Id { get; set; }

public int A_Version { get; set; }

public ICollection<DataModelB> Bs { get; set; } = [];
}

[PrimaryKey(nameof(B_Id), nameof(B_Version))]
public class DataModelB
{
public int B_Id { get; set; }

public int B_Version { get; set; }

public int A_Id { get; set; }
public ICollection<DataModelA> As { get; set; } = [];
}
[PrimaryKey(nameof(A_Id), nameof(A_Version))]
public class DataModelA
{
public int A_Id { get; set; }

public int A_Version { get; set; }

public ICollection<DataModelB> Bs { get; set; } = [];
}

[PrimaryKey(nameof(B_Id), nameof(B_Version))]
public class DataModelB
{
public int B_Id { get; set; }

public int B_Version { get; set; }

public int A_Id { get; set; }
public ICollection<DataModelA> As { get; set; } = [];
}
Note that both have a composite key, but they only join on half of the composite key, A_Id As a result, I could for example, have 5x DataModelA with A_Id = 1, and I could have 5x DataModelB with A_Id = 1, which would then produce a 5 <-> 5 relationship when I LEFT JOIN on this column. This pattern unfortunately is present across multiple tables on my db in this same way, the architect really liked to do this stuff and now I have to live with it and try and make it work with EF Core, I cannot modify the schema Current Solution Right now all over my database I have a bunch of Join operations like so:
var asToBs = db.As.Join(
db.Bs,
a => a.A_Id,
b => b.A_Id,
(a, b) => new { a, b }
)
var asToBs = db.As.Join(
db.Bs,
a => a.A_Id,
b => b.A_Id,
(a, b) => new { a, b }
)
Which works but its a lot of extra boilerplate as I have to do this for each navigation which very quickly produces a lot of code bloat to do basic stuff. I have tried to setup a property based navigation for this with the above schema but unfortunately it seems EF Core just has no API exposed to define a Many to Many relationship without an intermediary join table, and instead just define it as a basic LEFT JOIN from A to B. If anyone knows a way to do this, lemme know.
9 Replies
Angius
Angius3mo ago
Worst case scenario, move that custom join into an extension method on IQueryable EF, generally, works when your schema is by the book, so many to many with a join table, and so on Once you start straying from the "standard" you find yourself having to employ similarly non-standard workarounds
PixxelKick
PixxelKick3mo ago
Mostly what Id like is simply to just define a nav prop as a LEFT JOIN, which honestly should be a pretty normal thing to do
Angius
Angius3mo ago
Can also try asking in #database
PixxelKick
PixxelKick3mo ago
thats where I originally posted decided to move it over here since there was a lotta info and folks may wanna ref it later and I didnt wanna clog the chat up
leowest
leowest3mo ago
As a result, I could for example, have 5x DataModelA with A_Id = 1, and I could have 5x DataModelB with A_Id = 1, which would then produce a 5 <-> 5 relationship when I LEFT JOIN on this column.
By this u mean u can have say:
A1 B1
A1 B2
A1 B3
A1 B4
A1 B5
B1 A2
B1 A3
B1 A4
B1 A5
A1 B1
A1 B2
A1 B3
A1 B4
A1 B5
B1 A2
B1 A3
B1 A4
B1 A5
? just making sure
PixxelKick
PixxelKick3mo ago
I'm not sure what your example there translates too, tbh. But it'd be something like
| A_Id | A_Version |
|------|-----------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| A_Id | A_Version |
|------|-----------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| B_Id | B_Version | A_Id |
|------ |----------- |------ |
| 1 | 1 | 1 |
| 1 | 2 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 1 |
| B_Id | B_Version | A_Id |
|------ |----------- |------ |
| 1 | 1 | 1 |
| 1 | 2 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 1 |
If you join A on B on both tables' respective A_Id cols, you'd get a 5<->5 many to many
leowest
leowest3mo ago
B_Id A_Id
1 1
1 1
B_Id A_Id
1 1
1 1
And you can repeat ids like that? im not sure ef can do that out of the box
PixxelKick
PixxelKick3mo ago
yes because its a composite key. Table_A has a composite key of A_Id + A_Version, so you can have duplicates of A_Id but not duplicates of A_Id + A_Version combined
leowest
leowest3mo ago
Yeah I don't see a way to link these at model level unhappily
Want results from more Discord servers?
Add your server
More Posts
✅ GetGlobalApplicationCommandsAsync exceptionThe code in question ```c# IReadOnlyCollection<SocketApplicationCommand> commands = await this.m_DiNotifyIcon fails to appear sometimes when my app starts at user loginMy app: - .NET 7.0 Windows GUI app - uses WPF for some parts of the GUI - uses WinForms for other pa✅ Reducing code to separate UserControls for easier readability Avaloniacode: https://pastebin.com/zEFZNhip I'm wanting to learn how to break some of this screen down intTilemap too smallIm making a top-down game and am using a tilemap to make the map. It is way too small and i would apNon-Nullable field (WPF)Im currently using MVVM and trying to get the viewmodel to work namespace WPFLearning.MVVM.ViewModeDamage system isn't workingThis time I've got a far more precise issue, I'm trying to get this damage system to work however whMy player character is just getting launched into the sky despite not changing anything.I'm working on a project right now that has a ball roll around a map avoiding towers and trying to cVoiceover with Azure (Text-To-Speech)I'm trying to do a voiceover project with Azure. It speaks the entire text I write to the text file IEnumerable<T> (or List<T>, or T[]) to IEnumerable (non-generic, ie. no type param)?Hello, I'm working on some code that takes an `object` that may be either an object `T` itself, or sConverting HTML to PDF in .NET ApplicationsHi, can anyone suggest an open-source library that can convert an HTML file to PDF in the .NET frame