-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is it possible to define relationships that could reference one of multiple tables without foreign keys? #31913
Comments
@SoftCircuits this bears some resemblence to TPC (or possibly TPT) hierarchy modeling, where the foreign key can reference any of several tables (but there's no additional column to say which one). But in any case, no - EF navigations aren't compatible with your above scheme. You can of course perform the joining manually in your query by using the LINQ Join operator based on the value of FromType/ToType. Note that for this to be useful, you're likely modeling an inheritance hierarchy in the database; if the TransferTypes don't share any fields this wouldn't be very useful. At which point it begs the question of why the existing EF inheritance modeling strategies aren't good enough. |
@roji Thanks. I'm not modeling an inheritance hierarchy. I have several objects (tables) like It was becoming cumbersome to have So the Unfortunately, I've ran into issue after issue with this approach. At this point, I'd be pretty happy if there was a way to set it up so that I could write an expression that could get the related table without needing a reference to |
I do something similar in my code. I personally prefer not using joins because it complicates the caching story. I've seen this approach used in many apps on the Rails stack and it seems to work really well. It works great for me too. |
@TonyValenti that sounds like it needs to do an extra roundtrip to the database just to get the type and query the appropriate related table (roundtrips can have a considerable perf impact); if dependents also have such polymorphic dependents, that's another roundtrip etc. In any case, this discussion looks like a duplicate of #7623. |
Duplicate of #7623 |
Thanks, but I'm looking for ways to simplify my query. A new C# method would not be translatable to SQL and so it seems that would significantly complicate things. |
@roji Can I just ask this? Is there any way to define a navigation property without creating a foreign key constraint in the database? |
@SoftCircuits navigation properties aren't conceptually coupled to a constraint in the database. For example, you can use EF against a database that wasn't at all created with EF, and which has no constraints. EF would generate the same SQL - including the same JOINs; although nothing in the database enforces the referential integrity (since no constraint is defined), everything will generally work the same. However, the concept of a navigation is coupled to the concept of a foreign key; that is, to some value stored in a column that is identical to a key somewhere else. |
@roji Yes, I wonder if there would be utility in allowing EF to define navigation properties without creating those foreign keys. Then you could have something like the following where Of course, they could be null, and code would need to be written to determine which one is valid. class Person
{
public int VehicleId { get; set; }
public Car Car { get; set; }
public Truck Truck { get; set; }
public Motorcycle Motorcycle { get; set; }
} |
How do you propose EF decide which table to JOIN on? Something needs to say whether VehicleId points to a car, truck or motorcycle. |
@roji Based on the property I reference. If I reference As I described before, some responsibility is assumed by the developer. While another column would likely be used to indicate which table is referenced, this would be checked by the developer and not EF. But Perhaps these properties should always be considered nullable because there is no constraint to ensure they exist. |
I don't think that's a great design: it means that the user needs to know in advance - for a specific Person - which type of related vehicle it has. Since the user can only know that by looking at some other column in the Person row (VehicleType), at the very least this involves an extra roundtrip (once to fetch the Person and its vehicle type, another to fetch the vehicle). If the extra query and roundtrip are acceptable, then there seems to be little value here over what you can already do today: fetch the Person, and then fetch the related vehicle in a separate EF query based on the vehicle ID and type loaded in the first query. In this version of the feature, EF would be providing pretty thin sugar here, which I don't think would justify the feature. As a more valuable alternative, EF could be made aware of the vehicle type as a "discriminator", allowing it to load both the Person and the related vehicle in a single query (and roundtrip). Although better from a roundtrips perspective, the single query would be complex, as it would need to join the right table based on the vehicle type etc.; the optimal SQL and its performance would need to be carefully analyzed (across databases) before something like this would make sense. In short, polymorphic relationships is quite an open-ended field where many things are possible, and different users may want/need different things. We'd need to carefully design here and work out exactly what we want to provide; nothing's impossible technically, but there would a lot to think about. That's what #7623 generally tracks. |
@roji I don't believe it would require another round trip. A single SQL expression could be used that does the join and also checks another column. var people = DbContext.Persons
.Where(p => p.VehicleType == VehicleType.Truck)
.Select(p => p.Truck); It does put more responsibility on the developer, but no more than having to do all these joins manually using a separate reference to the I hit two roadblocks trying to work through my current task due to the fact that I needed another reference to If it was possible to have EF aware of |
@SoftCircuits that query above makes sense only if you very specifically want to get all people who have trucks along with their trucks. It doesn't work if you want to get some Person (e.g. whose name you have but nothing else), along with their vehicle of the correct kind. In any case, if the query above is what you want, then what else do you need from EF? It seems like you can already write precisely what you want as a LINQ query etc.
I don't really understand what this means or what it has to do with what we've been discussing here. |
I've twice run hit roadblocks needing a second reference to DbContext, as shown in the select clause below. var people = DbContext.Persons
.Where(p => p.VehicleType == VehicleType.Truck)
.Select(p => new
{
p.Name,
Truck = DbContext.Trucks
.Where(t => t.Id == p.VehicleId)
.Single()
});
Both of these problems would go away if there was a way to use a navigation property instead of a reference to |
@roji Anyway, I don't think I'm getting any traction on the specifics of what I'm saying. Certainly, some support for implied foreign keys like this would be a welcome addition. I will follow the related issue. |
@SoftCircuits just to put some summary points from my point of view:
I think the discussion here has run its course, but of course feel free to respond to any of the points above and I'll do my best to answer. For now I'll go ahead and close this as a duplicate. |
I have the following entity.
The
FromId
andToId
properties are foreign keys to another table. However, they can refer to one of several different tables. The table referenced by theFromId
property is determined by theFromType
property. And the table referenced by theToId
property is determined by theToType
property. So, for example, ifFromType
isTransferType.Railcar
, theFromId
property contains the ID of a row in the Railcars table.As a result, there is not an actual foreign key constraint defined in the database.
Is there any way to represent this in Entity Framework?
The ideal scenario would be if I could define a custom join to the Railcars table as
FromType == TransferType.Railcar && FromId == r.Id
.Short of that, is there anyway to define multiple references to other tables and signify that they are based off the same column?
In the end, I have reasons why my primary goal is to be able to write the navigation fields without referencing DbContext.
The text was updated successfully, but these errors were encountered: