-
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
Add DbFunctionParameter support for DbFunctions #14990
Conversation
@ajcvickers - Should DbFunction's parameter have ValueConverter also? |
I need to review this PR this weekend to make sure I didn't miss anything. I was not planning implementing the code which is going to use the new properties. Since the query pipeline is being rewritten it doesn't make sense to update the old one. @smitpatel - Does the new query work live in the smit/query branch? |
@pmiddleton - Yes, that is the branch. I was thinking the same that we can commit & merge API to master and new query pipeline will make use of it when rebased. It would be good if we have tests to verify the behavior but skipped in old pipeline. |
@smitpatel I think it needs to be possible to specify the actual type mapping to use (which could have a value converter on it) rather than only allowing the database type name. The database type name could be nice sugar for getting to the type mapping in common cases. |
@pmiddleton - I discussed with @ajcvickers about ValueConverters area. Essentially query needs TypeMapping for parameters so that it can generate literal/parameter correctly in SQL. So IDbFunctionParameter should store RelationalTypeMapping (& also IDbFunction should store RelationalTypeMapping as return type). Currently, there is no way to specify type mapping directly in fluent API. So for now we can have sugar method to specify database type and run a convention to assign type mapping whenever database type is set. TypeMappingConvention does the same for columns. |
Does it make more sense to look up the mappings at query translation time vs storing it? I am not completely familiar with the RelationalTypeMapping but is is possible for the mappings to be changed at runtime after model creation? If so then we shouldn't be precomputing and storing them. |
@pmiddleton - I believe we can differ that for now since IProperty also does not change TypeMapping at runtime. |
@smitpatel - Ok I will cache the values for parameters and return type, we can change to a realtime lookup later if needed. |
@smitpatel - Take a look now and let me know if this is what you had in mind for RelationalTypeMapping. If so I still need to add unit tests. |
Requesting review from @ajcvickers for what to store in function parameter for type mapping. |
/// 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 DatabaseType { 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.
Assuming this is the store type name, it probably doesn't need to be here in addition to the type mapping.
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.
Removed
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.
6159baa
to
52746ef
Compare
@smitpatel @ajcvickers - Rebased on latest master. Was there something else that needed changing for this PR before merging? Sorry I'm in process of trying to buy a house and move this spring so I haven't had as much time as I would like to work on things. |
@smitpatel Are we still waiting for anything here? |
src/EFCore/EFCore.csproj
Outdated
@@ -1,11 +1,12 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
|
|||
<PropertyGroup> | |||
<Description>Entity Framework Core is a lightweight and extensible version of the popular Entity Framework data access technology. | |||
<Description> |
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.
Seems like unrelated change
This should be outside of Translation == null check. Even if they are providing translation, they cannot pass in TypeMapping for the translated expression. Refers to: src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:84 in a99735f. [](commit_id = a99735f, deletion_comment = False) |
This should go away. All parameters on method info should be inside dbFunction.Parameters check below. And that loop should handle parameters Refers to: src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:94 in a99735f. [](commit_id = a99735f, deletion_comment = False) |
|
||
foreach (var parameter in dbFunction.Parameters) | ||
{ | ||
if(RelationalDependencies.TypeMappingSource.FindMapping(parameter.FunctionType) == 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.
We should first check if a typemapping is specified which can be mapped if not then only we should go and find mapping based on ClrType. That is applicable for both parameters and return value of actual function
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.
@smitpatel - Based on what you have said across these comments there won't be anything inside of the Translation == null check. Is this appropriate for the new query pipeline? Every parameter should have a type mapping, even if the translation is done manually?
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.
That is interesting question. Likely.
@@ -13,8 +14,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata | |||
/// </summary> | |||
public interface IDbFunction | |||
{ | |||
/// <summary> | |||
/// The name of the function in the database. | |||
/// <summary>,abase. |
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.
Typo
/// 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> | ||
Type FunctionType { get; } |
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.
Should just call this ClrType
/// <summary> | ||
/// Sets the name of the parameter | ||
/// </summary> | ||
public virtual DbFunctionParameterBuilder HasName([NotNull] string name) |
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.
Can parameter name be mutated? I would assume it would be same as parameter name you specify on your function.
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 leftover from when I originally wrote this a few years ago before I was auto pulling the values from the metadata.
That being said Oracle does support calling functions with named parameters. If for some reason the db function parameter name didn't match up with the code name then you could reset it. That assumes the backend Oracle provider would support this.
That can be an enhancement down the road and I will remove this.
@@ -74,6 +74,8 @@ public override ConventionSet CreateConventionSet() | |||
conventionSet.PropertyAddedConventions.Add(relationalColumnAttributeConvention); | |||
|
|||
var sharedTableConvention = new SharedTableConvention(logger); | |||
var dbFunctionTypeMappingConvention = new DbFunctionTypeMappingConvention(RelationalDependencies.TypeMappingSource); |
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.
Initialize closer to usage
/// </summary> | ||
public virtual InternalModelBuilder Apply(InternalModelBuilder modelBuilder) | ||
{ | ||
foreach (var dbFunc in modelBuilder.Metadata.Relational().DbFunctions.Cast<IMutableDbFunction>()) |
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.
nit:Prefer full name like dbFunction rather than Func
@@ -81,7 +84,7 @@ public class DbFunction : IMutableDbFunction, IMethodCallTranslator | |||
&& !typeof(DbContext).IsAssignableFrom(methodInfo.DeclaringType)) | |||
{ | |||
throw new ArgumentException( | |||
RelationalStrings.DbFunctionInvalidInstanceType(methodInfo.DisplayName(), methodInfo.DeclaringType.ShortDisplayName())); | |||
RelationalStrings.DbFunctionInvalidInstanceType(methodInfo.DisplayName(), methodInfo.DeclaringType?.ShortDisplayName())); |
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.
When would declaring type would be 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.
That's what I thought as well, however Resharper was giving me a "possible null assignment warning". I added the ? to shut it up.
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.
Add R# disable instead.
/// 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 DbFunctionParameterBuilder HasParameter([NotNull] string name) |
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.
@AndriySvyryd - Parameters are already defined looking at methodInfo. Here we want to get particular parameter to configure it. What should be right fluent way to do it? Calling HasParameter with name which is not any parameter in function throws
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 actually does not add any API to configure the parameter & functions return type's database type. Let me discuss with team and get back to you in terms of API shape and data storage necessary. |
When merging, check if #13782 is still needed. |
@smitpatel Did you confirm with the team that a return type parameter mapping on dbfunction is required? If so I will get it added in. |
@pmiddleton - I haven't got a chance yet. Give me about 2 more weeks to sort it out. Presently I am dealing with bigger chunks missing in new pipeline since it is blocking AspNetCore Identity to take new EF packages. |
@smitpatel - No problem. I am moving in 2 weeks so I don't have a ton of time right now myself. We will get this done in June. |
Design meeting decision: |
@pmiddleton - Would you have chance to complete this in next 1 week? If not I can take over and make modifications to merge. Release deadlines to meet. |
@smitpatel - sorry to do this to you, but I'm not going to be able to get to this in that time frame. Too much stuff to deal with from my move. We are still trying to stop living out of boxes :) |
@pmiddleton - No worries. I will wrap up the pending work. |
@pmiddleton - I have created #16182 |
@smitpatel Thanks for finishing this up for me. Sorry I wasn't able to get this done. |
Adds the ability to map properties for DbFunction parameters. See #13752