Skip to content

Commit

Permalink
Support abstract entity type in client, and fix some issues in client…
Browse files Browse the repository at this point in the history
… with

operations.
  • Loading branch information
Bin Xu committed Mar 20, 2015
1 parent 634325b commit a864902
Show file tree
Hide file tree
Showing 26 changed files with 2,558 additions and 1,713 deletions.
25 changes: 23 additions & 2 deletions src/CodeGen/ODataT4CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,7 @@ public ODataClientTemplate(CodeGenerationContext context)
internal abstract void WriteClassEndForEntityContainer();
internal abstract void WriteSummaryCommentForStructuredType(string typeName);
internal abstract void WriteKeyPropertiesCommentAndAttribute(IEnumerable<string> keyProperties, string keyString);
internal abstract void WriteEntityTypeAttribute();
internal abstract void WriteEntitySetAttribute(string entitySetName);
internal abstract void WriteEntityHasStreamAttribute();
internal abstract void WriteClassStartForStructuredType(string abstractModifier, string typeName, string originalTypeName, string baseTypeName);
Expand Down Expand Up @@ -1722,15 +1723,19 @@ internal void WriteEntityType(IEdmEntityType entityType, Dictionary<IEdmStructur
this.WriteClassEndForStructuredType();

this.WriteSummaryCommentForStructuredType(this.context.EnableNamingAlias ? Customization.CustomizeNaming(entityType.Name) : entityType.Name);

if (entityType.Key().Any())
{
IEnumerable<string> keyProperties = entityType.Key().Select(k => k.Name);
this.WriteKeyPropertiesCommentAndAttribute(
this.context.EnableNamingAlias ? keyProperties.Select(k => Customization.CustomizeNaming(k)) : keyProperties,
string.Join("\", \"", keyProperties));
}

else
{
this.WriteEntityTypeAttribute();
}

if (this.context.UseDataServiceCollection)
{
List<IEdmNavigationSource> navigationSourceList;
Expand Down Expand Up @@ -3902,6 +3907,14 @@ internal override void WriteKeyPropertiesCommentAndAttribute(IEnumerable<string>
this.Write("\")]\r\n");


}

internal override void WriteEntityTypeAttribute()
{

this.Write(" [global::Microsoft.OData.Client.EntityType()]\r\n");


}

internal override void WriteEntitySetAttribute(string entitySetName)
Expand Down Expand Up @@ -5882,6 +5895,14 @@ internal override void WriteKeyPropertiesCommentAndAttribute(IEnumerable<string>
this.Write("\")> _\r\n");


}

internal override void WriteEntityTypeAttribute()
{

this.Write(" <Global.Microsoft.OData.Client.EntityType()> _\r\n");


}

internal override void WriteEntitySetAttribute(string entitySetName)
Expand Down
23 changes: 21 additions & 2 deletions src/CodeGen/ODataT4CodeGenerator.ttinclude
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,7 @@ public abstract class ODataClientTemplate : TemplateBase
internal abstract void WriteClassEndForEntityContainer();
internal abstract void WriteSummaryCommentForStructuredType(string typeName);
internal abstract void WriteKeyPropertiesCommentAndAttribute(IEnumerable<string> keyProperties, string keyString);
internal abstract void WriteEntityTypeAttribute();
internal abstract void WriteEntitySetAttribute(string entitySetName);
internal abstract void WriteEntityHasStreamAttribute();
internal abstract void WriteClassStartForStructuredType(string abstractModifier, string typeName, string originalTypeName, string baseTypeName);
Expand Down Expand Up @@ -1615,15 +1616,19 @@ public abstract class ODataClientTemplate : TemplateBase
this.WriteClassEndForStructuredType();

this.WriteSummaryCommentForStructuredType(this.context.EnableNamingAlias ? Customization.CustomizeNaming(entityType.Name) : entityType.Name);

if (entityType.Key().Any())
{
IEnumerable<string> keyProperties = entityType.Key().Select(k => k.Name);
this.WriteKeyPropertiesCommentAndAttribute(
this.context.EnableNamingAlias ? keyProperties.Select(k => Customization.CustomizeNaming(k)) : keyProperties,
string.Join("\", \"", keyProperties));
}

else
{
this.WriteEntityTypeAttribute();
}

if (this.context.UseDataServiceCollection)
{
List<IEdmNavigationSource> navigationSourceList;
Expand Down Expand Up @@ -3522,6 +3527,13 @@ namespace <#= fullNamespace #>
<#+
}

internal override void WriteEntityTypeAttribute()
{
#>
[global::Microsoft.OData.Client.EntityType()]
<#+
}

internal override void WriteEntitySetAttribute(string entitySetName)
{
#>
Expand Down Expand Up @@ -4557,6 +4569,13 @@ Namespace <#= fullNamespace #>
<#+
}

internal override void WriteEntityTypeAttribute()
{
#>
<Global.Microsoft.OData.Client.EntityType()> _
<#+
}

internal override void WriteEntitySetAttribute(string entitySetName)
{
#>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ internal virtual Expression VisitQueryableResourceExpression(QueryableResourceEx

if (source != rse.Source)
{
rse = QueryableResourceExpression.CreateNavigationResourceExpression(rse.NodeType, rse.Type, source, rse.MemberExpression, rse.ResourceType, rse.ExpandPaths, rse.CountOption, rse.CustomQueryOptions, rse.Projection, rse.ResourceTypeAs, rse.UriVersion);
rse = QueryableResourceExpression.CreateNavigationResourceExpression(rse.NodeType, rse.Type, source, rse.MemberExpression, rse.ResourceType, rse.ExpandPaths, rse.CountOption, rse.CustomQueryOptions, rse.Projection, rse.ResourceTypeAs, rse.UriVersion, rse.OperationName, rse.OperationParameters);
}

return rse;
Expand Down
17 changes: 14 additions & 3 deletions src/Microsoft.OData.Client/ALinq/QueryableResourceExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,21 +242,32 @@ internal override ResourceExpression CreateCloneWithNewType(Type type)
/// <param name="projection">the projection expression</param>
/// <param name="resourceTypeAs">TypeAs type</param>
/// <param name="uriVersion">version of the Uri from the expand and projection paths</param>
/// <param name="operationName">The operation name.</param>
/// <param name="operationParameters">The operation parameter names and parameters pair for Resource</param>
/// <returns>The navigation resource expression.</returns>
internal static QueryableResourceExpression CreateNavigationResourceExpression(ExpressionType expressionType, Type type, Expression source, Expression memberExpression, Type resourceType, List<string> expandPaths, CountOption countOption, Dictionary<ConstantExpression, ConstantExpression> customQueryOptions, ProjectionQueryOptionExpression projection, Type resourceTypeAs, Version uriVersion)
internal static QueryableResourceExpression CreateNavigationResourceExpression(ExpressionType expressionType, Type type, Expression source, Expression memberExpression, Type resourceType, List<string> expandPaths, CountOption countOption, Dictionary<ConstantExpression, ConstantExpression> customQueryOptions, ProjectionQueryOptionExpression projection, Type resourceTypeAs, Version uriVersion, string operationName, Dictionary<string, string> operationParameters)
{
Debug.Assert(
expressionType == (ExpressionType)ResourceExpressionType.RootResourceSet || expressionType == (ExpressionType)ResourceExpressionType.ResourceNavigationProperty || expressionType == (ExpressionType)ResourceExpressionType.RootSingleResource,
"Expression type is not one of following: RootResourceSet, ResourceNavigationProperty, RootSingleResource.");

QueryableResourceExpression expression = null;

if (expressionType == (ExpressionType)ResourceExpressionType.RootResourceSet || expressionType == (ExpressionType)ResourceExpressionType.ResourceNavigationProperty)
{
return new ResourceSetExpression(type, source, memberExpression, resourceType, expandPaths, countOption, customQueryOptions, projection, resourceTypeAs, uriVersion);
expression = new ResourceSetExpression(type, source, memberExpression, resourceType, expandPaths, countOption, customQueryOptions, projection, resourceTypeAs, uriVersion);
}

if (expressionType == (ExpressionType)ResourceExpressionType.RootSingleResource)
{
return new SingletonResourceExpression(type, source, memberExpression, resourceType, expandPaths, countOption, customQueryOptions, projection, resourceTypeAs, uriVersion);
expression = new SingletonResourceExpression(type, source, memberExpression, resourceType, expandPaths, countOption, customQueryOptions, projection, resourceTypeAs, uriVersion);
}

if (expression != null)
{
expression.OperationName = operationName;
expression.OperationParameters = operationParameters;
return expression;
}

return null;
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OData.Client/ALinq/ResourceBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,7 @@ internal override Expression VisitQueryableResourceExpression(QueryableResourceE
// Debug.Assert(!rse.HasQueryOptions, "!rse.HasQueryOptions");

// since we could be adding query options to the root, create a new one which can be mutable.
return QueryableResourceExpression.CreateNavigationResourceExpression(rse.NodeType, rse.Type, rse.Source, rse.MemberExpression, rse.ResourceType, null /*expandPaths*/, CountOption.None, null /*customQueryOptions*/, null /*projection*/, rse.ResourceTypeAs, rse.UriVersion);
return QueryableResourceExpression.CreateNavigationResourceExpression(rse.NodeType, rse.Type, rse.Source, rse.MemberExpression, rse.ResourceType, null /*expandPaths*/, CountOption.None, null /*customQueryOptions*/, null /*projection*/, rse.ResourceTypeAs, rse.UriVersion, rse.OperationName, rse.OperationParameters);
}
return rse;
}
Expand Down
14 changes: 13 additions & 1 deletion src/Microsoft.OData.Client/ALinq/UriWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,19 @@ internal override Expression VisitQueryableResourceExpression(QueryableResourceE
{
if ((ResourceExpressionType)rse.NodeType == ResourceExpressionType.ResourceNavigationProperty)
{
this.Visit(rse.Source);
if (rse.IsOperationInvocation && !(rse.Source is QueryableResourceExpression))
{
var normalizerRewrites = new Dictionary<Expression, Expression>(ReferenceEqualityComparer<Expression>.Instance);
var e = Evaluator.PartialEval(rse.Source);
e = ExpressionNormalizer.Normalize(e, normalizerRewrites);
e = ResourceBinder.Bind(e, this.context);
this.Visit(e);
}
else
{
this.Visit(rse.Source);
}

this.uriBuilder.Append(UriHelper.FORWARDSLASH).Append(this.ExpressionToString(rse.MemberExpression, /*inPath*/ true));
}
else if (rse.MemberExpression != null)
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OData.Client/DataServiceContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ public DataServiceQuery<T> CreateFunctionQuery<T>(string path, string functionNa
{
Dictionary<string, string> operationParameters = this.SerializeOperationParameters(parameters);
ResourceSetExpression rse = new ResourceSetExpression(typeof(IOrderedQueryable<T>), null, Expression.Constant(path), typeof(T), null, CountOption.None, null, null, null, null, functionName, operationParameters, false);
return new DataServiceQuery<T>.DataServiceOrderedQuery(rse, new DataServiceQueryProvider(this));
return new DataServiceQuery<T>.DataServiceOrderedQuery(rse, new DataServiceQueryProvider(this), isComposable);
}

/// <summary>Creates a data service single query for function which return single data.</summary>
Expand Down
20 changes: 10 additions & 10 deletions src/Microsoft.OData.Client/DataServiceQueryOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ public class DataServiceQuery<TElement> : DataServiceQuery, IQueryable<TElement>
/// <summary>Linq Query Provider</summary>
private readonly DataServiceQueryProvider queryProvider;

/// <summary>
/// The flag of whether this query is a function.
/// </summary>
private readonly bool isFunction;

/// <summary>Uri, Projection, Version for translated query</summary>
private QueryComponents queryComponents;

Expand All @@ -58,7 +53,7 @@ public class DataServiceQuery<TElement> : DataServiceQuery, IQueryable<TElement>
public DataServiceQuery(Expression expression, DataServiceQueryProvider provider)
: this(expression, provider, true)
{
this.isFunction = false;
this.IsFunction = false;
}

/// <summary>
Expand All @@ -76,7 +71,7 @@ public DataServiceQuery(Expression expression, DataServiceQueryProvider provider
this.queryExpression = expression;
this.queryProvider = provider;
this.IsComposable = isComposable;
this.isFunction = true;
this.IsFunction = true;
}

#region IQueryable implementation
Expand Down Expand Up @@ -129,6 +124,11 @@ public DataServiceContext Context
/// </summary>
public bool IsComposable { get; private set; }

/// <summary>
/// The flag of whether this query is a function.
/// </summary>
internal bool IsFunction { get; private set; }

/// <summary>The ProjectionPlan for the request (if precompiled in a previous page).</summary>
internal override ProjectionPlan Plan
{
Expand Down Expand Up @@ -205,7 +205,7 @@ public string GetPath(string nextSegment)
/// <param name="state">User defined object used to transfer state between the start of the operation and the callback defined by <paramref name="callback" />.</param>
public new IAsyncResult BeginExecute(AsyncCallback callback, object state)
{
if (this.isFunction)
if (this.IsFunction)
{
return this.Context.BeginExecute<TElement>(this.RequestUri, callback, state, XmlConstants.HttpMethodGet, false);
}
Expand All @@ -228,7 +228,7 @@ public string GetPath(string nextSegment)
/// <exception cref="T:Microsoft.OData.Client.DataServiceQueryException">When the data service returns an HTTP 404: Resource Not Found error.</exception>
public new IEnumerable<TElement> EndExecute(IAsyncResult asyncResult)
{
if (this.isFunction)
if (this.IsFunction)
{
return this.Context.EndExecute<TElement>(asyncResult);
}
Expand Down Expand Up @@ -256,7 +256,7 @@ public Task<IEnumerable<TElement>> GetAllPagesAsync()
/// <exception cref="T:System.NotSupportedException">When during materialization an object is encountered in the input stream that cannot be deserialized to an instance of TElement.</exception>
public new IEnumerable<TElement> Execute()
{
if (this.isFunction)
if (this.IsFunction)
{
return this.Context.Execute<TElement>(this.RequestUri, XmlConstants.HttpMethodGet, false);
}
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.OData.Client/DataServiceQuerySingleOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ internal DataServiceQuerySingle(DataServiceQuery<TElement> query, bool isComposa
this.Query = query;
this.Context = query.Context;
this.IsComposable = isComposable;
this.isFunction = query.IsFunction;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ public static IEdmModel CreateODataServiceModel(string ns)
var productReviewSet = new EdmEntitySet(defaultContainer, "ProductReviews", productReviewType);
defaultContainer.AddElement(productReviewSet);

var orderType = new EdmEntityType(ns, "Order");
var abstractType = new EdmEntityType(ns, "AbstractEntity", null, true, false);
model.AddElement(abstractType);

var orderType = new EdmEntityType(ns, "Order", abstractType);
var orderIdProperty = new EdmStructuralProperty(orderType, "OrderID", EdmCoreModel.Instance.GetInt32(false));
orderType.AddProperty(orderIdProperty);
orderType.AddKeys(orderIdProperty);
Expand All @@ -177,7 +180,7 @@ public static IEdmModel CreateODataServiceModel(string ns)
var orderSet = new EdmEntitySet(defaultContainer, "Orders", orderType);
defaultContainer.AddElement(orderSet);

var orderDetailType = new EdmEntityType(ns, "OrderDetail");
var orderDetailType = new EdmEntityType(ns, "OrderDetail", abstractType);
var orderId = new EdmStructuralProperty(orderDetailType, "OrderID", EdmCoreModel.Instance.GetInt32(false));
orderDetailType.AddProperty(orderId);
orderDetailType.AddKeys(orderId);
Expand Down Expand Up @@ -523,6 +526,13 @@ public static IEdmModel CreateODataServiceModel(string ns)
getRelatedProductFunction.AddParameter("productDetail", new EdmEntityTypeReference(productDetailType, false));
model.AddElement(getRelatedProductFunction);

//Bound Function : Bound to Entity, Return Collection of Abstract Entity
var getOrderAndOrderDetails = new EdmFunction(ns, "getOrderAndOrderDetails",
new EdmCollectionTypeReference(new EdmCollectionType(new EdmEntityTypeReference(abstractType, false))),
true, new EdmPathExpression("customer/Orders"), true);
getOrderAndOrderDetails.AddParameter("customer", new EdmEntityTypeReference(customerType, false));
model.AddElement(getOrderAndOrderDetails);

//Bound Function : Bound to CollectionOfEntity, Return Entity
var getSeniorEmployees = new EdmFunction(ns, "GetSeniorEmployees",
new EdmEntityTypeReference(employeeType, true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,15 @@ public EntityCollection<Order> Orders
}
}

public abstract class AbstractEntity : ClrObject
{

}

/// <summary>
/// The class represents the Order model type.
/// </summary>
public class Order : ClrObject
public class Order : AbstractEntity
{
private EntityCollection<OrderDetail> orderDetails;

Expand Down Expand Up @@ -196,7 +201,7 @@ public void SetOrderShelfLifes(ODataCollectionValue values)
/// <summary>
/// The class represents the OrderDetail model type.
/// </summary>
public class OrderDetail : ClrObject
public class OrderDetail : AbstractEntity
{
public int OrderID { get; set; }
public int ProductID { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,22 @@ public IList<Order> PlaceOrders(Customer customer, IList<Order> orders)
return orders;
}

public IList<AbstractEntity> GetOrderAndOrderDetails(Customer customer)
{
var list = new List<AbstractEntity>();
list.AddRange(customer.Orders);
foreach (var order in customer.Orders)
{
foreach (var od in order.OrderDetails)
{
od.EntitySetName = "OrderDetails";
list.Add(od);
}
}

return list;
}

public Collection<string> ResetBossEmail(List<string> emails)
{
var boss = GetRootQuery("Boss") as Customer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ protected ClrObject()
public DateTime UpdatedTime { get; set; }

public List<InstanceAnnotationType> Annotations { get; set; }

public string EntitySetName { get; set; }
}

[Serializable]
Expand Down
Loading

0 comments on commit a864902

Please sign in to comment.