Skip to content
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

Closed
wants to merge 1 commit into from

Conversation

pmiddleton
Copy link
Contributor

Adds the ability to map properties for DbFunction parameters. See #13752

@smitpatel
Copy link
Contributor

@ajcvickers - Should DbFunction's parameter have ValueConverter also?
One weird issue which can come in the absence of it, is if you are passing a column vs a constant. They both would have different types.

@pmiddleton
Copy link
Contributor Author

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?

@smitpatel
Copy link
Contributor

@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.

@ajcvickers
Copy link
Contributor

@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.

@smitpatel
Copy link
Contributor

@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.

@pmiddleton
Copy link
Contributor Author

@smitpatel

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.

@smitpatel
Copy link
Contributor

@pmiddleton - I believe we can differ that for now since IProperty also does not change TypeMapping at runtime.

@pmiddleton
Copy link
Contributor Author

@smitpatel - Ok I will cache the values for parameters and return type, we can change to a realtime lookup later if needed.

@pmiddleton
Copy link
Contributor Author

@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.

@smitpatel smitpatel requested a review from ajcvickers March 26, 2019 23:55
@smitpatel
Copy link
Contributor

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; }
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is still appearing for me in codeflow review.


In reply to: 272869029 [](ancestors = 272869029)

@pmiddleton pmiddleton changed the title WIP - Add DbFunctionParameter support for DbFunctions Add DbFunctionParameter support for DbFunctions Apr 8, 2019
@pmiddleton pmiddleton force-pushed the dbparameter branch 4 times, most recently from 6159baa to 52746ef Compare April 8, 2019 03:05
@pmiddleton
Copy link
Contributor Author

@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.

@ajcvickers
Copy link
Contributor

@smitpatel Are we still waiting for anything here?

@@ -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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like unrelated change

@smitpatel
Copy link
Contributor

                if (RelationalDependencies.TypeMappingSource.FindMapping(methodInfo.ReturnType) == null)

This should be outside of Translation == null check. Even if they are providing translation, they cannot pass in TypeMapping for the translated expression.
Also see below for parameter


Refers to: src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:84 in a99735f. [](commit_id = a99735f, deletion_comment = False)

@smitpatel
Copy link
Contributor

                    if (RelationalDependencies.TypeMappingSource.FindMapping(parameter.ParameterType) == null)

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)
Copy link
Contributor

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

Copy link
Contributor Author

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?

Copy link
Contributor

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.
Copy link
Contributor

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; }
Copy link
Contributor

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)
Copy link
Contributor

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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>())
Copy link
Contributor

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()));
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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)
Copy link
Contributor

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

Copy link
Contributor

@smitpatel smitpatel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕐

@smitpatel
Copy link
Contributor

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.
Columns remember the annotation which specify string format of the type on database. If we don't store that info, I am not sure how would we get type mapping source to use that info to set the type mapping accurately.

@ajcvickers
Copy link
Contributor

ajcvickers commented May 11, 2019

When merging, check if #13782 is still needed.

@pmiddleton
Copy link
Contributor Author

@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.

@smitpatel
Copy link
Contributor

@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.

@pmiddleton
Copy link
Contributor Author

@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.

@smitpatel
Copy link
Contributor

smitpatel commented Jun 14, 2019

Design meeting decision:
There will be API taking string type name only. Which would map to TypeMapping.
HasType is the name of API for parameters
HasReturnType for function.

@smitpatel
Copy link
Contributor

@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.

@pmiddleton
Copy link
Contributor Author

@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 :)

@smitpatel
Copy link
Contributor

@pmiddleton - No worries. I will wrap up the pending work.

@smitpatel
Copy link
Contributor

@pmiddleton - I have created #16182
Thanks for contribution.

@smitpatel smitpatel closed this Jun 21, 2019
@pmiddleton
Copy link
Contributor Author

@smitpatel Thanks for finishing this up for me. Sorry I wasn't able to get this done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants