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
[WIP] - Shared-Type Entities Update Pipeline #14057
Conversation
…able. Can do insert, update and delete but not select yet.
/// </summary> | ||
/// <returns> the shared-type EntityType corresponding to this instance if found in the model, or null if not. </returns> | ||
IEntityType FindSharedTypeEntityType([NotNull] object entityInstance); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering about making this a Chain-Of-Responsibility pattern by adding a NextFinder
getter/setter. That way if you are using multiple different patterns of identifying a Shared-Type-EntityType from instance in your context you can set up multiple of these chained together in the order you want to apply them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that would be necessary, this logic shouldn't be replaced or extended and it shouldn't need to change often. Furthermore it's in a perf-sensitive part of the code and keeping all the patterns for finding the EntityType in one class will be slightly faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see your point. Don't agree that it shouldn't be replaced or extended. I'd be really surprised if different users of this functionality are completely happy with just the one way of doing it. It was not even agreed among us that the index property was the only way to go. That said I take your point on perf (though we do cache the result of course) and maybe we could wait on Chain-Of-Responsibility til we get feedback from customers.
: Model.FindEntityType(entityTypeName); | ||
|
||
return entityType != null && entityType.IsSharedType ? entityType : null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could add a FindSharedTypeEntityType(string name)
method on Model
and use that instead of the above?
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual string EntityTypeNamePropertyName { get; [NotNull]set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to be writable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually thought was a nice feature, It just allows you to pick a different argument to the indexer - other than "__EntityTypeName__" - which I kind of picked at random.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One would need to do that in the constructor, allowing to do it afterwards could easily lead to inconsistency in the model.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also since it's overridable derived classes can just replace it with a different value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is true that users could get themselves in trouble if they changed the value half way through. I was just trying to make it simple - so they didn't have to write a whole new class just to change that one value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we really want to make this simple to configure we should add sugar API that doesn't require messing with services at all, perhaps something on DbContextOptions
@@ -155,7 +157,8 @@ public virtual InternalEntityEntry GetOrCreateEntry(object entity) | |||
{ | |||
_trackingQueryMode = TrackingQueryMode.Multiple; | |||
|
|||
var entityType = _model.FindRuntimeEntityType(entity.GetType()); | |||
var entityType = _sharedTypeEntityFinder.FindSharedTypeEntityType(entity) | |||
?? _model.FindRuntimeEntityType(entity.GetType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_model.FindRuntimeEntityType(entity.GetType())
can be moved into the SharedTypeEntityFinder
implementation and it could be renamed to EntityTypeFinder
.
Are you planning to implement other type finding strategies? Is there a tracking issue that lists them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I'm following. This service is meant to find Shared-Type EntiyTypes only. I did have an idea for another one of those - which is for a CLR-type which is shared, and has an indexer for the other properties, but could have a known, fixed-name CLR-property for the EntityType name. But I hadn't discussed that with @ajcvickers or @divega yet and I seem to remember one of them had a 3rd idea on how we should do this. Basically I can see people wanting to identify Shared-Type entities in various different ways and wanted to make it as easy as possible to write your own service if you wanted to.
But I did not intend to change or make into a service the existing functionality to find EntityTypes using their CLR-type. There are 6 methods already existing on Model
which do that in various different ways. Did you want to encapsulate all of that somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I would like to avoid having to special case Shared type entity types as much as possible and here this can by accomplished by making the service look for non-shared types as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also implement the strategy that uses a normal property and have the name passed in the constructor or a overridable readonly property.
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public class InternalSharedTypeDbSet<TEntity> : InternalDbSet<TEntity> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could just add EntityTypeName
to InternalDbSet
, no need to add another type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean add EntityTypeName
to InternalDbSet
, then add a constructor that takes the name, assign to EntityTypeName
in that constructor and later use the fact that EntityTypeName
is set to distinguish when trying to find the EntityType
? That would be possible. It's true I didn't like having to make various things protected. to make this work But this seemed cleaner to me - during e.g. debugging I can immediately see what this is representing - but I'm open to the possibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I just want to reduce special casing and handling this in one class would result in less code and less code means there are fewer places to introduce bugs.
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual bool IsSharedType { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be readonly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was just following the same pattern as used for IsQueryType
. See Model.AddQueryType()
and then AddSharedTypeEntityType()
immediately below it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we would need to change IsQueryType
too. Changing the value for either after the type is already in the model could leave it in an incosistent state, since it would avoid the checks done in AddSharedType
and AddQueryType
DO NOT COMMIT THIS - work in progress.
Wanted to get some feedback on the work on Shared-Type Entity Types (#9914). So far I've updated the
Model
to have a newAddSharedEntityType()
method to be used duringOnModelCreating()
; updatedDbContext
to allow specifying a Shared-Type-DbSet which uses thatEntityType
; and using that you can insert, update and delete those entities (Note: query not implemented yet).As part of this I created a new service
ISharedTypeEntityFinder
. This is used by theStateManager
, when given an entity instance, to associate that instance with a Shared-Type-EntityType defined duringOnModelCreating()
. At the moment there is only one implementation of this service - which identifies the instance by expecting it to have a property-indexer (see #13610) which takes a specific (but configurable) argument and which returns the name of theEntityType
which it represents; however the service is replaceable - so other implementations are possible.Added and updated some tests. More functional tests will be needed but wanted to get feedback first.