在一个表中查找条目,在另一个表中进行搜索

时间:2019-07-05 11:35:35

标签: c# asp.net-core .net-core entity-framework-core

我正在尝试使用Entity Framework Core和ASP.NET Core制作Web API

我有一个用户配置文件表(称为featUsers)和一个方案表(称为“方案”)。首先,我想基于一个字段查找一个用户,然后返回与该用户关联的方案列表。

返回所有方案都可以:

// GET: api/Scenarios
[HttpGet]
public async Task<ActionResult<IEnumerable<Scenario>>> Getscenarios()
{
    return await _context.scenarios.ToListAsync();
}

修改它以测试具有特定外键的搜索和返回方案也可以正常工作:

// GET: api/Scenarios
[HttpGet]
public async Task<ActionResult<IEnumerable<Scenario>>> Getscenarios()
{
    return await _context.scenarios.Where(scenario => scenario.FeatUserId == 1).ToListAsync();
}

但是当我进一步修改它以首先找到用户概要文件,然后使用该概要文件查找场景时,事情就倒了。该函数的外观如下:

// GET: api/Scenarios
[HttpGet]
public async Task<ActionResult<IEnumerable<Scenario>>> Getscenarios()
{
    //Find the profile, with specific Identity ID
    var featProfile = _context.featUsers.FirstOrDefault(u => u.IdentityId == "44fc0698-9f99-46dd-bfac-db1781fd8b01");

    //Debug
    Console.WriteLine(featProfile.FeatUserId);

    //Return all the scenarios which are related to that profile above
    return await _context.scenarios.Where(scenario => scenario.FeatUserId == featProfile.FeatUserId).ToListAsync();
}

当我用Postman查询此端点时(Console.WriteLine正确地向终端写入了“ 1”,这是预期的,但是)这是我在Postman中得到的响应:

Newtonsoft.Json.JsonSerializationException: Self referencing loop detected with type 'DAF_FEAT.Models.Scenario'. Path '[0].featUser.scenarios'.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
   at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
   at IdentityServer4.Hosting.MutualTlsTokenEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS
=======
Cache-Control: no-cache
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate
Host: localhost:5001
User-Agent: PostmanRuntime/7.15.0
Postman-Token: c3ba03bb-8f2f-433a-998a-e13cd361f888

为完整起见,模型如下:

    public class FeatUser
    {
        public int FeatUserId { get; set; }
        public string Role { get; set; }
        public string OrganisationName { get; set; }
        public string PhoneNumber { get; set; }

        public string IdentityId { get; set; }

        public List<Scenario> Scenarios { get; set; }
    }

    public class Scenario
    {
        public int ScenarioId { get; set; }
        public string Name { get; set; }
        public DateTime DateCreated { get; set; }
        public DateTime DateUpdated { get; set; }
        public bool Active { get; set; }

        public int FeatUserId { get; set; }
        public FeatUser FeatUser { get; set; }
    }

也许我要解决所有这些错误,并且应该通过做类似以下的事情来利用导航属性:

return (await _context.featUsers.Include(u => u.Scenarios).FirstOrDefaultAsync(u => u.IdentityId == userId)).Scenarios.ToList();

1 个答案:

答案 0 :(得分:0)

正如DavidG在其评论中建议的那样,您不应在api中返回EF模型。您应该为模型创建DTO(数据传输对象),然后返回它们。您的DTO不应具有自引用循环(FeatUser包含场景,然后Scenario包含FeatUser)。因此,在您的示例中,您的DTO如下所示:

public class FeatUserDto
{
    public int FeatUserId { get; set; }
    public string Role { get; set; }
    public string OrganisationName { get; set; }
    public string PhoneNumber { get; set; }

    public string IdentityId { get; set; }

    public List<ScenarioDto> Scenarios { get; set; }
}

public class ScenarioDto
{
    public int ScenarioId { get; set; }
    public string Name { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateUpdated { get; set; }
    public bool Active { get; set; }
}

请注意,ScenarioDto如何不包含指向FeatUserDto的链接,以避免自引用循环。

现在剩下的是将模型映射到DTO。 Automapper可以帮上忙。