-
Notifications
You must be signed in to change notification settings - Fork 352
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
Key Alias support #2411
base: release-7.x
Are you sure you want to change the base?
Key Alias support #2411
Conversation
9589777
to
c282be8
Compare
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Serialization/EdmModelCsdlSchemaJsonWriter.cs
Outdated
Show resolved
Hide resolved
ed1f40b
to
aa2c3a1
Compare
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Parsing/Ast/CsdlPropertyReference.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Parsing/Ast/CsdlPropertyReference.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs
Outdated
Show resolved
Hide resolved
@@ -157,6 +158,37 @@ public void AddKeys(IEnumerable<IEdmStructuralProperty> keyProperties) | |||
this.declaredKey = new List<IEdmStructuralProperty>(); | |||
} | |||
|
|||
//The Key property is the last segment in the path segment. | |||
IEdmStructuralPropertyAlias structuralPropertyAlias = property as IEdmStructuralPropertyAlias; | |||
if (!string.IsNullOrEmpty(structuralPropertyAlias?.PropertyAlias)) |
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 the logic in this block be placed in a location where it can be shared given that it looks similar to that in src/Microsoft.OData.Edm/Csdl/Semantics/CsdlSemanticsEntityTypeDefinition.cs?
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.
Even better, could the new EdmStructuralPropertyAlias
type take in the constructor the IEdmStructuralProperty
that it's an alias for? Then we wouldn't have to traverse the Path
sequence multiple times, and we could also not store the Path
as an IEnumerable
in EdmStructuralPropertyAlias
, but instead as string
. Except for this method, we always use Path
in string.Join('/', Path)
, so if we could just store the original string instead, we would save all of those Join
calls.
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.
Actually, I think it makes the most sense to go one step further even: the EdmStructuralPropertyAlias
constructor should do this work, otherwise there are far too many validations that need to happen in order to ensure the EdmStructuralPropertyAlias
is not malformed.
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.
See my comment on the constructor, there just so much validation that would need to happen
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.
The EdmStructuralPropertyAlias
is not the property
with an alias in this case.
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.
@ElizabethOkerio but PropertyAliasHelpers.GetKeyProperty()
returns an IEdmStructuralPropertyAlias
, right? And here you already have an IEdmStructuralPropertyAlias
.
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.
@habbes The IEdmStructuralPropertyAlias
is for the first segment but this method PropertyAliasHelpers.GetKeyProperty()
returns IEdmStructuralPropertyAlias
for the last segment..
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.
Okay, I see the IEdmStructuralPropertyAlias
doesn't include the type of the target property, but EdmStructuralPropertyAlias
. Makes sense to the traversal then.
But maybe we should have a fast path alternative when this happens to be an EdmStructuralPropertyAlias
(which seems quite likely to be the case most of the times) to avoid creating a (possibly) dublicate EdmStructuralPropertyAlias
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.
@habbes am not sure I understand this. So we are the ones who create the EdmStructuralPropertyAlias
once we've gotten to the last segment on the path.
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.
Am not sure there is any fast way of getting the last segment.. When we call the AddKeys
method, we pass in the first segment property and the path. So to get to the last segment we have to traverse the whole path. If we decide on passing the last segment property to the AddKeys
method, that will mean we are assuming the path is valid and no path traversal is needed.
string pName = ""; | ||
string pValue = ""; | ||
v.ParseAsObject(p, (keyAlias, keyName) => | ||
{ | ||
pName = keyName.ParseAsString(p); | ||
pValue = keyAlias; | ||
}); | ||
|
||
return new CsdlPropertyReference(pName, pValue, context.Location()); |
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.
Is there any other scenario where we reach this branch? The ReportError
message doesn't seem specific to this specific feature (even if the comment is specific to the feature). Maybe we should be more a little bit more defensive, something like:
string pName = ""; | |
string pValue = ""; | |
v.ParseAsObject(p, (keyAlias, keyName) => | |
{ | |
pName = keyName.ParseAsString(p); | |
pValue = keyAlias; | |
}); | |
return new CsdlPropertyReference(pName, pValue, context.Location()); | |
bool error = false; | |
string pName = null; | |
string pValue = null; | |
v.ParseAsObject(p, (keyAlias, keyName) => | |
{ | |
if (pName != null || pValue != null) | |
{ | |
error = true; | |
return; | |
} | |
pName = keyName.ParseAsString(p); | |
pValue = keyAlias; | |
}); | |
if (error || pName == null || pValue == null) | |
{ | |
p.ReportError(EdmErrorCode.InvalidKeyValue, "It doesn't support the key object."); | |
} | |
else | |
{ | |
return new CsdlPropertyReference(pName, pValue, context.Location()); | |
} |
Alternatively, we could do some Debug.Assert
s if we want to be a little more flexible, but that might actually result in bigger issues for customers if something goes wrong.
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.
so before we were returning the error because the feature was not supported. Now that the feature is being supported, there is no need to return the error. That's if an object is found then it is parsed. There is a check
if(v.ValueKind == JsonValueKind.Object)
.
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 guess I'm just making sure that the only time we return that error is because the feature was not supported. Is that right?
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.
Since the feature is supported, I think that error message would be misleading. If we want to validate against null key or value, I think the error message should be adjusted accordingly.
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 the key be null? I assume that would be invalid JSON?
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.
the key cannot be null here.
else | ||
{ | ||
structuralProperty = this.FindProperty(keyProperty.PropertyName) as IEdmStructuralProperty; | ||
} |
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.
The nested if
above means that we won't always reach this branch even if we should fallback to the existing behavior.
else | |
{ | |
structuralProperty = this.FindProperty(keyProperty.PropertyName) as IEdmStructuralProperty; | |
} | |
structuralProperty = structuralProperty ?? this.FindProperty(keyProperty.PropertyName) as IEdmStructuralProperty; |
IEdmStructuralProperty structuralProperty = null; | ||
if (!string.IsNullOrEmpty(keyProperty?.Alias)) | ||
{ | ||
string[] keyPropertySegments = keyProperty.PropertyName.Split('/'); |
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.
How much can we trust the validation to have happened at this point? Is it possible we split a string like "foo//bar"? Because then we might have an empty string in keyPropertySegments
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.
Because we are the ones creating this string and not the client - I think we should take care of all this things at the point of creating the string when writing to the csdl. I can add more validations there maybe.
/// <param name="alias">The property alias.</param> | ||
/// <param name="path">The path to the referenced property.</param> | ||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "string", Justification = "defaultValue might be confused for an IEdmValue.")] | ||
public EdmStructuralPropertyAlias(IEdmStructuredType declaringType, string name, IEdmTypeReference type, string alias, IEnumerable<string> path) |
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.
With all of this being public
, we should probably validate everything. For example, don't we need to check the consistency of declaringType
, name
, and type
? And shouldn't name
always be the last element of path
? And shouldn't path
always have at least two elements?
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.
@corranrogue9 Most of the validations are done when the base
gets called. Like the declaringType
and type
. The name
is the first element of the path. This is the complex property
in the entity type that acts like a base
for the path to the type
that has the primitive type
which will be used as key for the entity type.
I agree we need to add validations mostly on the path
- if it has more than one element? etc.
/// <returns>Created structural property.</returns> | ||
public EdmStructuralPropertyAlias AddStructuralPropertyAlias(IEdmTypeReference type, string alias, IEnumerable<string> path) | ||
{ | ||
string propertyName = path.FirstOrDefault(); |
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.
Shouldn't it be the last element in path
?
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.
@corranrogue9 This is the complex property that is being added to the entity type and not the key property. The key property is what is the last element in the path. This method was specifically added to support adding a complex property which is a link to a property(which in this case is the key
property) with an alias
public EdmStructuralPropertyAlias AddStructuralPropertyAlias(IEdmTypeReference type, string alias, IEnumerable<string> path) | ||
{ | ||
string propertyName = path.FirstOrDefault(); | ||
EdmStructuralPropertyAlias property = new EdmStructuralPropertyAlias(this, propertyName, type, alias, path); |
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 probably confirm that this
type does indeed have properties that follow path
and result in a property with name propertyName
and of type 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.
Am not sure I understand this. So, here we are adding a property - propertyName
of type type
to this
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.
I'm sure most of my comments around this has been nonsensical regarding what an alias means, but I think
my points stands. Hopefully this example will help make sure I'm understanding correctly. There is a type buzz
with a property foo/bar/fizz
that is of type Edm.Decimal
. The caller wishes to add an alias to buzz
called frob
that points to foo/bar/fizz
.
In this case, doesn't frob
have to be of type Edm.Decimal
? If that's the case, then what I'm suggesting is that we need to walk the path
parameter in this method to ensure that:
- Each segment of the path is in fact valid for
this
- The type of the property pointed to by
path
must matchtype
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.
The key
for the type buzz
is not in buzz
. The key is in another type let's say fizz
. But the type buzz
has a complex property bar
whose type is fizz
and fizz
has a property Id
whose type is Edm.Int
and which is the key for buzz
. This is a 2-segment path. we could have a longer segment than that but that should be the flow. So the key for buzz
will be represented as bar/Id
. The alias is an identifier for this path bar/Id
. Instead of using this path, we use an alias which does not have the slashes and that is easy to work with. The Alias will always be a string. The only segment of the path that is valid for this
is the first segment. The other segments belong to other types.
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.
so the method AddStructuralPropertyAlias
is used to add bar
to buzz
when creating the model
but because this property bar
acts as a link to the actual key
property for type buzz
, and is not the key for type buzz
, that's why we provide more information to it like the alias and the key path. The path is later processed to get to the last path segment to get the real key
property for the 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.
@ElizabethOkerio are there tests that verify that model validation is able to detect errors related to invalid property alias paths or types?
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.
For performance, open/close principle, and single-responsibility reasons, even if the model validation catches it, the logic should move to the constructor.
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.
@corranrogue9 I had @xuzhg mention that by design EDM does not validate the model unless the user explicitly chooses to do so. But maybe the context was different.
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 logic is used in computing the declared key. I don't know whether it can move to the constructor.
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.
@corranrogue9 So when we are adding the complex property
to the model, we call AddStructuralPropertyAlias
. Within this method we call EdmStructuralPropertyAlias
. We can move the logic for checking the path and everything to the constructor. This will check for validity of the path. When we call AddKeys
method for adding the key to the model, if we say that we pass in the last segment on the path and not do any validation because we already did it in the constructor, I think this will open up some loopholes where someone can just pass in something that is not even part of the path. That's why when we are adding the keys to the entity type's DeclaredKey
, we still have to go through the path and make sure that whatever we are adding to the DeclaredKey
is in the path and is the last segment on the path.
136ca5e
to
1c8eaf6
Compare
string pName = ""; | ||
string pValue = ""; | ||
v.ParseAsObject(p, (keyAlias, keyName) => | ||
{ | ||
pName = keyName.ParseAsString(p); | ||
pValue = keyAlias; | ||
}); | ||
|
||
return new CsdlPropertyReference(pName, pValue, context.Location()); |
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 the key be null? I assume that would be invalid JSON?
src/Microsoft.OData.Edm/Csdl/Serialization/EdmModelCsdlSchemaJsonWriter.cs
Outdated
Show resolved
Hide resolved
{ | ||
internal static class PropertyAliasHelpers | ||
{ | ||
internal static IEdmStructuralProperty GetKeyProperty(IEdmStructuralProperty property, string[] keyPropertySegments, string propertyAlias) |
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: From the perspective of this method, it doesn't seem to make a difference whether the property is part of a key or not. I think a different name would be more appropriate. I don't have
a good candidate top of mind. Maybe something in the lines of CreatePropertyAliasFromSegments(startingProperty, propertySegments (or propertyPathSegments), alias)
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 method loops through the path segments to get to the last segment which is the key property.
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 method does not know that it's a key property, it only knows that it's a property at the end of the path. It's the caller of this method that has decided to use that property as part of a key. But nothing about this method (other than the parameter and method names) link it to a key.
@@ -157,6 +158,37 @@ public void AddKeys(IEnumerable<IEdmStructuralProperty> keyProperties) | |||
this.declaredKey = new List<IEdmStructuralProperty>(); | |||
} | |||
|
|||
//The Key property is the last segment in the path segment. | |||
IEdmStructuralPropertyAlias structuralPropertyAlias = property as IEdmStructuralPropertyAlias; | |||
if (!string.IsNullOrEmpty(structuralPropertyAlias?.PropertyAlias)) |
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.
@ElizabethOkerio what was the conclusion to this thread?
@@ -157,6 +158,37 @@ public void AddKeys(IEnumerable<IEdmStructuralProperty> keyProperties) | |||
this.declaredKey = new List<IEdmStructuralProperty>(); | |||
} | |||
|
|||
//The Key property is the last segment in the path segment. | |||
IEdmStructuralPropertyAlias structuralPropertyAlias = property as IEdmStructuralPropertyAlias; | |||
if (!string.IsNullOrEmpty(structuralPropertyAlias?.PropertyAlias)) |
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'm confused a bit. If the property here is already an IEdmStructuralPropertyAlias
why do you need to possibly duplicate EdmStructuralPropertyAlias
via PropertyAliasHelpers.GetKeyProperty()
instead of adding the property directly to the declared key?
@habbes so if it IEdmStructuralPropertyAlias
then it means there is a path,, and the key is the last segment in that path. That's why we have to go through the whole path in this method PropertyAliasHelpers.GetKeyProperty()
to get to the last segment which will be the key..And that's what we'll add to DeclaredKey
public EdmStructuralPropertyAlias AddStructuralPropertyAlias(IEdmTypeReference type, string alias, IEnumerable<string> path) | ||
{ | ||
string propertyName = path.FirstOrDefault(); | ||
EdmStructuralPropertyAlias property = new EdmStructuralPropertyAlias(this, propertyName, type, alias, path); |
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.
@ElizabethOkerio are there tests that verify that model validation is able to detect errors related to invalid property alias paths or types?
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? 👍 :ok_hand: :thumbsdown: (Email) |
// "$Key": [ | ||
// { | ||
// "EntityInfoID": "Info/ID" | ||
// } | ||
// ] |
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 have removed these lines as you removed the TODO, no?
// "$Key": [ | ||
// { | ||
// "EntityInfoID": "Info/ID" | ||
// } | ||
// ] | ||
p.ReportError(EdmErrorCode.InvalidKeyValue, "It doesn't support the key object."); | ||
string pName = ""; |
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.
Is there a variable by the name propertyName
in scope such that we cannot use that in place of pName
?
// "$Key": [ | ||
// { | ||
// "EntityInfoID": "Info/ID" | ||
// } | ||
// ] | ||
p.ReportError(EdmErrorCode.InvalidKeyValue, "It doesn't support the key object."); | ||
string pName = ""; | ||
string pValue = ""; |
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.
Is there a variable by the name propertyValue
in scope such that we cannot use that in place of pValue
?
} | ||
|
||
} |
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.
} | |
} | |
} | |
} |
return null; | ||
} | ||
|
||
structuralProperty = PropertyAliasHelpers.GetKeyProperty(structuralProperty, keyPropertySegments, keyProperty.PropertyAlias); |
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.
Given that structuralProperty
was assigned a value 5 or 6 line above here, could you add a comment above here to give someone an idea what happens when you call PropertyAliasHelpers.GetKeyProperty
and what new value structuralProperty
assumes.
On line 124 at least it's clear that, given Info/ID
, structural property will be assigned a reference to the Info
property... On this line it's not clear what is happening
IEdmStructuralPropertyAlias prop = property as IEdmStructuralPropertyAlias; | ||
if (prop == null) | ||
{ | ||
this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, property.Name, EdmValueWriter.StringAsXml); | ||
} | ||
else | ||
{ | ||
this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, string.Join("/", prop.Path), EdmValueWriter.StringAsXml); | ||
this.WriteRequiredAttribute(CsdlConstants.Attribute_Alias, prop.PropertyAlias, EdmValueWriter.StringAsXml); | ||
} |
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.
IEdmStructuralPropertyAlias prop = property as IEdmStructuralPropertyAlias; | |
if (prop == null) | |
{ | |
this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, property.Name, EdmValueWriter.StringAsXml); | |
} | |
else | |
{ | |
this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, string.Join("/", prop.Path), EdmValueWriter.StringAsXml); | |
this.WriteRequiredAttribute(CsdlConstants.Attribute_Alias, prop.PropertyAlias, EdmValueWriter.StringAsXml); | |
} | |
if (property is IEdmStructuralPropertyAlias prop) | |
{ | |
this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, string.Join("/", prop.Path), EdmValueWriter.StringAsXml); | |
this.WriteRequiredAttribute(CsdlConstants.Attribute_Alias, prop.PropertyAlias, EdmValueWriter.StringAsXml); | |
} | |
else | |
{ | |
this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, property.Name, EdmValueWriter.StringAsXml); | |
} |
{ | ||
this.jsonWriter.WriteStartObject(); | ||
this.jsonWriter.WritePropertyName(propertyAlias.PropertyAlias); | ||
this.jsonWriter.WriteStringValue(string.Join("/", propertyAlias.Path)); |
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 join
operation is done in quite a few places. Could we have taken care of it by including a readonly
property to the IEdmStructuralPropertyAlias
interface and it's derivations that returns the concatenated thing? We could even apply an optimization there by doing the concatenation only once when the getter is first called and saving the result in a private field
/// </summary> | ||
public class EdmStructuralPropertyAlias : EdmProperty, IEdmStructuralPropertyAlias | ||
{ | ||
private string propertyAlias; |
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.
Make propertyAlias
readonly
public class EdmStructuralPropertyAlias : EdmProperty, IEdmStructuralPropertyAlias | ||
{ | ||
private string propertyAlias; | ||
private IEnumerable<string> path; |
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.
Make path
readonly
public EdmStructuralPropertyAlias(IEdmStructuredType declaringType, string name, IEdmTypeReference type, string propertyAlias, IEnumerable<string> path) | ||
: base(declaringType, name, type) | ||
{ | ||
if (propertyAlias == 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.
Is an empty string valid as property alias?
throw new ArgumentNullException(nameof(propertyAlias)); | ||
} | ||
|
||
if (path == 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.
Is an empty collection valid as path?
{ | ||
internal static class PropertyAliasHelpers | ||
{ | ||
internal static IEdmStructuralProperty GetKeyProperty(IEdmStructuralProperty property, string[] keyPropertySegments, string propertyAlias) |
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.
Document this method so it's clear what it does
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.
Is this method called from multiple places? If no, would it have been better for it to reside in the class from where it's called seeing it's the only method in this class and file...
IEdmStructuralProperty structuralProperty = property; | ||
for (int i = 1; i < keyPropertySegments.Length; i++) | ||
{ | ||
if (structuralProperty.Type.Definition.TypeKind == EdmTypeKind.Complex) |
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 have used a switch...
return structuralProperty; | ||
|
||
} |
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.
return structuralProperty; | |
} | |
return structuralProperty; | |
} |
if (structuralProperty != null) | ||
{ | ||
IEdmStructuralProperty prop = PropertyAliasHelpers.GetKeyProperty(structuralProperty, keyPropertySegments, structuralPropertyAlias.PropertyAlias); | ||
if (prop != 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.
There's nothing we should do if prop
is null?
} | ||
string propertyName = path.FirstOrDefault(); |
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.
} | |
string propertyName = path.FirstOrDefault(); | |
} | |
string propertyName = path.FirstOrDefault(); |
/// <returns>Created structural property.</returns> | ||
public EdmStructuralPropertyAlias AddStructuralPropertyAlias(IEdmTypeReference type, string alias, IEnumerable<string> path) | ||
{ | ||
if (path == 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.
Is an empty collection valid as path?
@ElizabethOkerio Let's kick it off again: here's my thought: Basically, we can add a new interface: public interface IEdmPropertyRef: IEdmNamedElement
{
IEdmProperty Property { get; set; }
string Path { get; set; } // or IEdmPathExpression
string Alias { get; set; }
} So, change: public class EdmEntityType
{
- private List<IEdmStructuralProperty> declaredKey;
+ private List<IEdmPropertyRef> declaredKey;
+ public void AddKeys(params IEdmPropertyRef[] keyProperties)
+ {}
+ public void AddKeys(params IEdmPropertyRef[] keyProperties)
+ {}
} Change the existing AddKeys, and add others. |
Issues
This pull request fixes #xxx.
Key Alias support in ODL
Here's an example for Key alias:
EntityInfoID
is the alias andInfo/ID
is the path to the key.Changes made in this PR:
New interfaces and Classes;
IEnumerable Path { get; }
andstring PropertyAlias { get; }
EdmStructuredType
Added a new method
public EdmStructuralPropertyAlias AddStructuralPropertyAlias(IEdmTypeReference type, string alias, IEnumerable path) - This is the method that users will use to add key aliases.
EdmEntityType
In the
AddKeys(IEnumerable keyProperties)
method, when looping through each property, we cast it into anIEdmStructuralPropertyAlias
and check if the key has an alias or not. If it does, we loop through the keyProperties till we get to the last path segment which is the key and create anEdmStructuralPropertyAlias
and add it to the declaredKeys IEnumerable.Description
Briefly describe the changes of this pull request.
Checklist (Uncheck if it is not completed)
Additional work necessary
If documentation update is needed, please add "Docs Needed" label to the issue and provide details about the required document change in the issue.