-
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
Support inheritance for owned/property bag/shared-type entity types #9630
Comments
We would need API on |
It took me so much time to get to this issue. I am having a problem in which a owned type generates a Discriminator property, even though there is no need for it, since the class that has this property is not derived anywhere else. Can this be the same issue? I tried removing it from migration and from the snapshot to test, but it generates a wrong sql statement when acessing the DbContext on that Set. Is there any way to get around this, without generating the property on the database? |
@andre-f-paggi Please file a new issue and include a runnable project/solution or complete code listing that demonstrates the behavior you are seeing. |
@ajcvickers I can look at supplying a runnable solution if it will assist getting it resolved quicker |
@chris-stormideas We understand what this issue is about--i.e. inheritance mapping into a shared table is not supported. The feature is currently on the backlog, and not considered very high priority. The best way to influence getting it resolved is probably to make a case for why this specific mapping is so important. |
What about collections of owned types, where the owned-collection is polymorphic? public class Order
{
public List<Position> Positions { get; set; } // Owned collection
}
public abstract class Position
{ }
public class FancyPosition : Position
{ }
public class StandardPosition : Position
{ }
public class SampleContext : DbContext
{
public virtual DbSet<Order> Orders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
modelBuilder.Entity<Order>().OwnsMany(p => p.Positions);
}
} Is this implicitly tracked by this issue or would you recommend creating a new issue for this? |
@AndriySvyryd Thoughts on polymorphic owned collections? |
Polymorphic owned collections will be covered by this, but similar to non-collections all derived types will need to be configured explicitly. |
Polymorphic owned collections do provide the ability to compose our object model which is really quite nice. I have a project I have been waiting to migrate over to efcore that currently uses Horrible InHouse Awful ORM (tm) that I wrote years ago much to today me's regret. This is the only feature left that I cant really support with efcore. |
@digitalpowers For now we can only say that it won't happen this year. |
Thanks for the feedback. If polymorphic owned collections are covered by this issue, I would recommend updating the issue title+description so that users can find this. ATM it is not really clear and looks like it only covers inline owned types. Thanks! |
@AndriySvyryd Does this issue also cover the case where I explicitly want to set a Example:
In this particular example, |
@Lobosque Yes |
Also because it forces you to tightly couple unrelated parts of your code in some common situations. |
Any update on this? Especially with Cosmos Db Provider it's very likely to need inheritance on owned collection types. |
@AndiHahn This issue is in the Backlog milestone. This means that it is not planned for the next release (EF Core 7.0). We will re-assess the backlog following the this release and consider this item at that time. However, keep in mind that there are many other high priority features with which it will be competing for resources. Make sure to vote (👍) for this issue if it is important to you. |
Eeeshhh, this still isn't on the board? It seems like such a basic feature for any kind of non anemic modeling. I constantly bump up against this, search to see if there's an update, and find this issue on GitHub. I've even unvoted and voted for it multiple times. Come on guys, this stinks. Somehow, stored procedure support in EF has gotten more attention, even when it's perfectly viable to drop to ADO.NET to execute. |
I would ask in #29252. In sumary, I wanted to have a value object status for an order. I want to follow the state pattern. Then to map in EF Core I need to configure the status as owned entity. But I need to configure also the derived classes, but I don't know how to do. Then my question is. Is it possible to configure EF Core for state pattern when the state is a value object? If not, perhaps the another option would be to use the state as entity, but then the domain is affected by the database, and I would like to avoid this option if it would be possible. Thanks. |
@ComptonAlvaro I don't think it's currently possible to do what you are asking. |
@ajcvickers Thanks for you help. Then if actually is not possible, perhaps in the future? And now, which could be an alternative? 1.- Don't use state pattern in the domain Thanks. |
@ComptonAlvaro Hard to say, since it's your code and your architecture, but my initial impression is to just keep things simple, which probably means not using the state pattern. |
Just wanted to post up and example that I think showcases how much benefit having inheritance specified on owned types could have. For a two-case discriminated union that allows setting two different types, each of which refers to a different entity (referential relation in this case): public abstract record Target {
public record ReferenceTarget( EntityReference Reference ) : Target; // style 1: linked entity only
public record ContentTarget( string ContentID, Content Content ) : Target; // style 2: linked entity and foreign key
} that would ideally only have the following property defined in the POCO model: public class SomeDomainModel {
...
public Target Target { get; private set; } // if owned type inheritance was supported
...
} we currently have to work around this by mapping all the properties to DAL-only properties and use a property wrapper that switches on the model and nulls out all the non-shared properties/columns between them. public class SomeDomainModel {
...
public Target Target {
get => TargetType switch {
nameof(Target.ReferenceTarget) => new Target.ReferenceTarget( Reference! ),
nameof(Target.ContentTarget) => new Target.ContentTarget( ContentID!, Content! ),
_ => throw new NotSupportedException( $"Unknown target type '{TargetType}'" ),
};
set {
(string, EntityType?, string?, string?, EntityReference?, string?, Content?) persistedValue = value switch {
Target.ReferenceTarget referenceTarget => (
TargetType: nameof(Target.ReferenceTarget),
ReferenceType: referenceTarget.Reference.Type,
ReferenceProvider: referenceTarget.Reference.Provider,
ReferenceID: referenceTarget.Reference.ID,
Reference: referenceTarget.Reference,
// NOTE: we null out non-common properties of other sub-classes
ContentID: null,
Content: null
),
Target.ContentTarget contentTarget => (
TargetType: nameof(Target.ContentTarget),
// NOTE: we null out non-common properties of other sub-classes
ReferenceType: null,
ReferenceProvider: null,
ReferenceID: null,
Reference: null,
ContentID: contentTarget.ContentID,
Content: contentTarget.Content
),
_ => throw new NotSupportedException( $"Unknown identity type '{value.GetType().Name}'" ),
};
(TargetType, ReferenceType, ReferenceProvider, ReferenceID, Reference, ContentID, Content) = persistedValue;
}
}
/*DAL*/internal string TargetType { get; private set; }
// NOTE: composite foreign key
/*DAL*/internal EntityType? ReferenceType { get; private set; }
/*DAL*/internal string? ReferenceProvider { get; private set; }
/*DAL*/internal string? ReferenceID { get; private set; }
/*DAL*/internal EntityReference? Reference { get; private set; }
/*DAL*/internal string? ContentID { get; private set; }
/*DAL*/internal Content? Content { get; private set; }
...
} Note that Ideally the EF configuration could be set up so that the underlying columns that get mapped are still a flattened set of the combined sub-class columns similar to what happens for TPH on a non-owned entity:
This would require letting EF know above the known sub-classes (or it discovering them) so that it can "flatten" the hierarchy into nullable columns and add in the discriminator column. Please note that the code above is required for a single property of our main model ( For other domain models, we have similar patterns but are okay with them being JSON blobs rather than flattened columns – in which case unfortunately EF doesn't support that either (#27779) |
I just wanted to register my interest in support for this exact scenario |
is any input needed to help decide if this makes the cut for the current release? It is still the only thing preventing me from migrating to efcore and I very much want to :) |
What's the chance we might see this in EF Core 9? |
@chrisc-ona None - 9 is done |
@ErikEJ well hopefully we'll have it in 10 then |
For example, this from #9536:
This is ambiguous as to whether LessThanFriend.CityAddress should be mapped to allow inheritance such that either a CityAddress or a FullAddress could be persisted. Typically, we only map inheritance when both types are in the model. However, having both types in the model as Owned types on different entities perhaps does not have the same semantics--especially when thinking of them like complex types.
Based on triage discussion from #9536, we think we want to support both the simple mapping (just persisting given concrete type, which is what the request on #9536 is for) and the inheritance mapping, which would require, for TPH, and additional discriminator column in the table. We did not come to a final decision on which should be the default, or what the new API will look like to switch between the two.
The text was updated successfully, but these errors were encountered: