Skip to content

Commit 7f03890

Browse files
committed
Modify to fix issue for #2076, Containment expand problem
1 parent e5410e8 commit 7f03890

File tree

8 files changed

+170
-21
lines changed

8 files changed

+170
-21
lines changed

samples/AspNetCore3xEndpointSample.Web/AspNetCore3xEndpointSample.Web.csproj

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
</PropertyGroup>
66

77
<ItemGroup>
8-
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
8+
<PackageReference Include="EntityFramework" Version="6.4.0" />
9+
<!--<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
910
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.0" />
10-
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="3.1.0" />
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="3.1.0" />-->
1112
</ItemGroup>
1213

1314
<ItemGroup>

samples/AspNetCore3xEndpointSample.Web/Controllers/CustomersController.cs

+83-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
using AspNetCore3xEndpointSample.Web.Models;
77
using Microsoft.AspNet.OData;
88
using Microsoft.AspNetCore.Mvc;
9-
using Microsoft.EntityFrameworkCore;
9+
1010

1111
namespace AspNetCore3xEndpointSample.Web.Controllers
12-
{
12+
{/*
1313
public class CustomersController : ODataController
1414
{
1515
private readonly CustomerOrderContext _context;
@@ -87,4 +87,85 @@ public IActionResult Get(int key)
8787
return Ok(_context.Customers.FirstOrDefault(c => c.Id == key));
8888
}
8989
}
90+
*/
91+
public class CustomersController : ODataController
92+
{
93+
private readonly IList<Customer> _customers;
94+
95+
public CustomersController(/*CustomerOrderContext context*/)
96+
{
97+
_customers = new List<Customer>
98+
{
99+
new Customer
100+
{
101+
ID = 123,
102+
CustomerReferrals = new List<CustomerReferral>
103+
{
104+
new CustomerReferral { ID = 8, CustomerID = 123, ReferredCustomerID = 8},
105+
new CustomerReferral { ID = 9, CustomerID = 123, ReferredCustomerID = 9},
106+
},
107+
Phones = Enumerable.Range(0, 2).Select(e =>
108+
new CustomerPhone { ID = 11, CustomerID = 123, Formatted = new CustomerPhoneNumberFormatted { CustomerPhoneNumberID = 17, FormattedNumber = "171" } }
109+
).ToList()
110+
},
111+
new Customer
112+
{
113+
ID = 456,
114+
CustomerReferrals = new List<CustomerReferral>
115+
{
116+
new CustomerReferral { ID = 18, CustomerID = 456, ReferredCustomerID = 8},
117+
new CustomerReferral { ID = 19, CustomerID = 456, ReferredCustomerID = 9},
118+
},
119+
Phones = Enumerable.Range(0, 2).Select(e =>
120+
new CustomerPhone { ID = 21 + e, CustomerID = 456 + e, Formatted = new CustomerPhoneNumberFormatted { CustomerPhoneNumberID = 17 + e, FormattedNumber = "abc" } }
121+
).ToList()
122+
},
123+
//new Customer
124+
//{
125+
// Name = "Peter",
126+
// HomeAddress = new Address { City = "Hollewye", Street = "Main St NE"},
127+
// FavoriteAddresses = new List<Address>
128+
// {
129+
// new Address { City = "R4mond", Street = "546 NE"},
130+
// new Address { City = "R4d", Street = "546 AVE"},
131+
// },
132+
// Order = new Order { Title = "Jichan" },
133+
// Orders = Enumerable.Range(0, 2).Select(e => new Order { Title = "ijk" + e }).ToList()
134+
//},
135+
};
136+
137+
foreach (var customer in _customers)
138+
{
139+
foreach (var refed in customer.CustomerReferrals)
140+
{
141+
refed.ReferredCustomer = customer;
142+
refed.Customer = customer;
143+
}
144+
}
145+
146+
}
147+
148+
[EnableQuery]
149+
public IActionResult Get()
150+
{
151+
// Be noted: without the NoTracking setting, the query for $select=HomeAddress with throw exception:
152+
// A tracking query projects owned entity without corresponding owner in result. Owned entities cannot be tracked without their owner...
153+
// _context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
154+
155+
return Ok(_customers);
156+
}
157+
158+
[EnableQuery]
159+
public IActionResult Get(int key)
160+
{
161+
return Ok(_customers.FirstOrDefault(c => c.ID == key));
162+
}
163+
164+
[EnableQuery(MaxExpansionDepth = 5)]
165+
public IActionResult GetCustomerReferrals(int key)
166+
{
167+
var c = _customers.FirstOrDefault(c => c.ID == key);
168+
return Ok(c.CustomerReferrals);
169+
}
170+
}
90171
}

samples/AspNetCore3xEndpointSample.Web/Models/CustomerOrder.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33

44
using System.Collections.Generic;
55
using System.ComponentModel.DataAnnotations.Schema;
6-
using Microsoft.EntityFrameworkCore;
76

87
namespace AspNetCore3xEndpointSample.Web.Models
9-
{
8+
{/*
109
public class Customer
1110
{
1211
public int Id { get; set; }
@@ -35,5 +34,5 @@ public class Address
3534
public string City { get; set; }
3635
3736
public string Street { get; set; }
38-
}
37+
}*/
3938
}
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,35 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4-
using Microsoft.EntityFrameworkCore;
4+
//using Microsoft.EntityFrameworkCore;
5+
6+
using System.Data.Entity;
57

68
namespace AspNetCore3xEndpointSample.Web.Models
79
{
810
public class CustomerOrderContext : DbContext
911
{
10-
public CustomerOrderContext(DbContextOptions<CustomerOrderContext> options)
11-
: base(options)
12+
//public CustomerOrderContext(DbContextOptions<CustomerOrderContext> options)
13+
// : base(options)
14+
//{
15+
//}
16+
17+
public CustomerOrderContext(string connectString)
18+
: base(connectString)
1219
{
1320
}
1421

1522
public DbSet<Customer> Customers { get; set; }
1623

17-
public DbSet<Order> Orders { get; set; }
24+
// public DbSet<Order> Orders { get; set; }
1825

19-
protected override void OnModelCreating(ModelBuilder modelBuilder)
26+
protected override void OnModelCreating(DbModelBuilder modelBuilder)
2027
{
21-
modelBuilder.Entity<Customer>().OwnsOne(c => c.HomeAddress).WithOwner();
28+
modelBuilder.Entity<CustomerPhone>().HasOptional(a => a.Formatted).WithRequired();
29+
modelBuilder.Entity<Customer>()
30+
.HasMany(c => c.CustomerReferrals)
31+
.WithRequired(c => c.Customer)
32+
.HasForeignKey(c => c.CustomerID);
2233
}
2334
}
2435
}

samples/AspNetCore3xEndpointSample.Web/Models/EdmModelBuilder.cs

+56-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
using Microsoft.AspNet.OData.Builder;
55
using Microsoft.OData.Edm;
6+
using System.Collections.Generic;
7+
using System.ComponentModel.DataAnnotations;
8+
using System.ComponentModel.DataAnnotations.Schema;
69

710
namespace AspNetCore3xEndpointSample.Web.Models
811
{
@@ -15,13 +18,64 @@ public static IEdmModel GetEdmModel()
1518
if (_edmModel == null)
1619
{
1720
var builder = new ODataConventionModelBuilder();
18-
builder.EntitySet<Customer>("Customers");
19-
builder.EntitySet<Order>("Orders");
21+
var customers = builder.EntitySet<Customer>("Customers");
22+
customers.Binding.HasManyPath(c => c.CustomerReferrals, true).HasRequiredBinding(r => r.ReferredCustomer, "Customers");
23+
// builder.EntitySet<Order>("Orders");
2024
_edmModel = builder.GetEdmModel();
2125
}
2226

2327
return _edmModel;
2428
}
2529

2630
}
31+
32+
public class Customer
33+
{
34+
[Key]
35+
public int ID { get; set; }
36+
37+
[Contained]
38+
public virtual ICollection<CustomerReferral> CustomerReferrals { get; set; }
39+
40+
[Contained]
41+
public virtual ICollection<CustomerPhone> Phones { get; set; }
42+
}
43+
44+
public class CustomerReferral
45+
{
46+
[Key]
47+
public int ID { get; set; }
48+
49+
public int CustomerID { get; set; }
50+
51+
public int ReferredCustomerID { get; set; }
52+
53+
[Required]
54+
[ForeignKey(nameof(CustomerID))]
55+
public virtual Customer Customer { get; set; }
56+
57+
[Required]
58+
[ForeignKey(nameof(ReferredCustomerID))]
59+
public virtual Customer ReferredCustomer { get; set; }
60+
}
61+
62+
public class CustomerPhone
63+
{
64+
[Key]
65+
public int ID { get; set; }
66+
67+
[Editable(false)]
68+
public int CustomerID { get; set; }
69+
70+
[Contained]
71+
public virtual CustomerPhoneNumberFormatted Formatted { get; set; }
72+
}
73+
74+
public class CustomerPhoneNumberFormatted
75+
{
76+
[Key]
77+
public int CustomerPhoneNumberID { get; set; }
78+
79+
public string FormattedNumber { get; set; }
80+
}
2781
}

samples/AspNetCore3xEndpointSample.Web/Startup.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4-
using System;
5-
using System.Collections.Generic;
64
using AspNetCore3xEndpointSample.Web.Models;
75
using Microsoft.AspNet.OData.Batch;
86
using Microsoft.AspNet.OData.Extensions;
@@ -11,12 +9,13 @@
119
using Microsoft.AspNetCore.Builder;
1210
using Microsoft.AspNetCore.Hosting;
1311
using Microsoft.AspNetCore.Http;
14-
using Microsoft.EntityFrameworkCore;
1512
using Microsoft.Extensions.Configuration;
1613
using Microsoft.Extensions.DependencyInjection;
1714
using Microsoft.Extensions.Hosting;
1815
using Microsoft.OData;
1916
using Microsoft.OData.Edm;
17+
using System;
18+
using System.Collections.Generic;
2019

2120
namespace AspNetCore3xEndpointSample.Web
2221
{
@@ -32,7 +31,8 @@ public Startup(IConfiguration configuration)
3231
// This method gets called by the runtime. Use this method to add services to the container.
3332
public void ConfigureServices(IServiceCollection services)
3433
{
35-
services.AddDbContext<CustomerOrderContext>(opt => opt.UseLazyLoadingProxies().UseInMemoryDatabase("CustomerOrderList"));
34+
//services.AddDbContext<CustomerOrderContext>(opt => opt.UseLazyLoadingProxies().UseInMemoryDatabase("CustomerOrderList"));
35+
//services.AddScoped<CustomerOrderContext>(_ => new CustomerOrderContext(Configuration.GetConnectionString("DefaultConnection")));
3636
services.AddOData();
3737
services.AddRouting();
3838
}
@@ -54,6 +54,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
5454

5555
app.UseEndpoints(endpoints =>
5656
{
57+
endpoints.Expand();
5758
endpoints.MapODataRoute(
5859
"nullPrefix", null,
5960
b =>

samples/AspNetCore3xEndpointSample.Web/appsettings.json

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{
2+
"ConnectionStrings": {
3+
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=EF6MVCCore;Trusted_Connection=True;MultipleActiveResultSets=true"
4+
},
25
"Logging": {
36
"LogLevel": {
47
"Default": "Information",

src/Microsoft.AspNet.OData.Shared/Query/ODataQueryOptions.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ private void Initialize(ODataQueryContext context)
7373

7474
_queryOptionParser = new ODataQueryOptionParser(
7575
context.Model,
76-
context.ElementType,
77-
context.NavigationSource,
76+
context.Path.Path,
7877
normalizedQueryParameters);
7978

8079
// Note: the context.RequestContainer must be set by the ODataQueryOptions constructor.

0 commit comments

Comments
 (0)