【问题标题】:Struggling with adding or removing items to a custom Result<T> object努力向自定义 Result<T> 对象添加或删除项目
【发布时间】:2021-04-02 07:57:48
【问题描述】:

这把我逼上绝路了,即使是朝着正确方向的最微小的推动也会非常感激。

基本上,此方法调用第三方 API 来获取给定用户的预订列表,然后我想将其与预订 ID 和会员编号的链接表进行比较,以与传递给该方法的 loggedInMemberNumber 匹配并且只返回由登录用户进行的预订。

我的问题是我不知道如何使用第一个响应 - 我要创建列表的预订 ID 存储在 response.Response.Data.Id 但 Result 和 Dto 对象的建模令人困惑(对我来说诚然是缺乏经验的眼睛!),我不知道应该如何添加到模型中才能正确导航。

Intelisense 可以看到 response.Response.Data 和 response.Response.Included 但没有添加或删除项目的方法。我是否必须向模型添加自定义类才能实现这一点?怎么样?

获取:

public async Task<IActionResult> GetBookingForUser(string policyNumber, string memberNumber, string loggedInMemberNumber)
    {
        if (!string.IsNullOrEmpty(policyNumber) && !string.IsNullOrEmpty(memberNumber) && !string.IsNullOrEmpty(loggedInMemberNumber))
        {
            var response = new Result<BookingListDto>();

            var getUserResponse = await _medicalSolutionsRepository.GetMedicalSolutionsUserIdOrRegisterUser(memberNumber, policyNumber, false);
            if (getUserResponse.Success)
            {
                response = await _medicalSolutionsRepository.GetBookingsForUser(getUserResponse.Response.UserId.ToString());

                if (!response.Success)
                {
                    return BadRequest(response);
                }

                var loggedInMemberBookings = _apiDbContext.MedicalSolutionsBookings;
                List<long> bookingIdsByLoggedInUser = new List<long>();

                foreach (var booking in loggedInMemberBookings)
                {
                    if (booking.MemberNumber == loggedInMemberNumber)
                    {
                        bookingIdsByLoggedInUser.Add(booking.BookingId);
                    }
                }

                //This is where I want to create an object to store the correct bookings from the original response
                Result<BookingListDto> correctBookings = new Result<BookingListDto>();

                foreach (var responseBookingData in response.Response.Data)
                {
                    foreach (var bookingId in bookingIdsByLoggedInUser)
                    {
                        if (responseBookingData.Id == bookingId)
                        {
                            //This is where I fall apart, Data has no method to add or remove items
                            correctBookings.Response.Data.Add(responseBookingData);
                        }
                    }
                }

                // Included needs to be filled with these values also
                foreach (var responseBookingIncluded in response.Response.Included)
                {
                    foreach (var bookingId in bookingIdsByLoggedInUser)
                    {
                        if (responseBookingIncluded.Id == bookingId)
                        {
                           
                            correctBookings.Response.Data.Add(responseBookingIncluded);
                        }
                    }
                }

                response.Response.Data = correctBookings.Response.Data;
                response.Response.Included = correctBookings.Response.Included;
            }

            return ApiOk(response);
        }

        return ApiBadRequest("UserId is a required field");

    }

结果模型:

    public class Result
{
    [JsonProperty("success")]
    public bool Success { get; set; }
    [JsonProperty("message")]
    public string Message { get; set; }
    [JsonProperty("errors")]
    public IEnumerable<Error> Errors { get; set; }
    [JsonProperty("first_error")]
    public Error FirstError => Errors?.FirstOrDefault();
    [JsonProperty("status_code")]
    public int StatusCode { get; set; }

    public Result()
    { }

    protected Result(bool success, HttpStatusCode statusCode, string message = null) : this(success, statusCode, message, Enumerable.Empty<Error>()) { }

    protected Result(bool success, HttpStatusCode statusCode, string message, IEnumerable<Error> errors)
    {
        Success = success;
        StatusCode = (int)statusCode;
        Message = message;
        Errors = errors ?? Enumerable.Empty<Error>();
    }

    public static Result Ok(HttpStatusCode statusCode) => new Result(true, statusCode);
    public static Result Ok(HttpStatusCode statusCode, string message) => new Result(true, statusCode, message);
    public static Result Fail(HttpStatusCode statusCode) => new Result(false, statusCode);
    public static Result Fail(HttpStatusCode statusCode, string message) => new Result(false, statusCode, message);
    public static Result Fail(HttpStatusCode statusCode, string message, IEnumerable<Error> errors) => new Result(false, statusCode, message, errors);
}

public class Result<T> : Result
{
    public T Response { get; set; }

    //[JsonConstructor]
    public Result()
    {
        
    }

    protected Result(bool success, HttpStatusCode statusCode, T data) : this(success, statusCode, data, null) { }

    protected Result(bool success, HttpStatusCode statusCode, T data, string message) : this(success, statusCode, data, message, Enumerable.Empty<Error>()) { }

    protected Result(bool success, HttpStatusCode statusCode, T data, string message, IEnumerable<Error> errors) : base(success, statusCode, message, errors)
    {
        Response = data;
    }


    public static Result<T> Ok(T data, HttpStatusCode statusCode)
    {
        return new Result<T>(true, statusCode, data);
    }

    public static Result<T> Ok(T data, HttpStatusCode statusCode, string message)
    {
        return new Result<T>(true, statusCode, data, message);
    }

    public new static Result<T> Fail(HttpStatusCode statusCode)
    {
        return new Result<T>(false, statusCode, default(T));
    }

    public static Result<T> Fail(T data, HttpStatusCode statusCode, string message)
    {
        return new Result<T>(false, statusCode, data, message);
    }

    public static Result<T> Fail(string message, HttpStatusCode statusCode)
    {
        return new Result<T>(false, statusCode, default(T), message);
    }

    public static Result<T> Fail(string message, HttpStatusCode statusCode, IEnumerable<Error> errors)
    {
        return new Result<T>(false, statusCode, default(T), message, errors);
    }
}

Dto 模型:

public partial class BookingListDto 
{
    [JsonProperty("data")]
    public IEnumerable<Data> Data { get; set; }
    [JsonProperty("included")]
    public IEnumerable<Included> Included { get; set; }
}
public partial class Included
{
    [JsonProperty("type")]
    public string Type { get; set; } = "appointments";

    [JsonProperty("id")]
    public long Id { get; set; }

    [JsonProperty("attributes")]
    public IncludedAttributes Attributes { get; set; }

}

public partial class Data
{
    [JsonProperty("type")]
    public string Type { get; set; } = "bookings";

    [JsonProperty("id")]
    public long Id { get; set; }

    [JsonProperty("attributes")]
    public Attributes Attributes { get; set; }

    [JsonProperty("relationships")]
    public Relationships Relationships { get; set; }
}

【问题讨论】:

  • 你的 Data 类没有实现任何接口,例如IList 会提供这样的行为,也没有任何这样的方法。
  • 您调用的服务中的 json 是什么样的?您希望服务中的 json 是什么样的?
  • ps;拥有 jsonProperty 属性的好处之一是,您可以为您的属性省去这些非常平淡/无意义的名称,并称它们为有助于您理解代码的东西,但让输出的 json 适当地无意义(把罐子踢下去)给不得不使用它的可怜的开发人员)-除非您也定义了 json,在这种情况下,我建议使用更好的名称
  • 还有; efcore 标签与这个 Q 相关吗?

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


【解决方案1】:

对于您正在解决的问题,通过了解LINQ,您将受益匪浅。我将在下面给出的示例是使用该技术的“扩展方法”版本。

假设_apiDbContext 类似于实体框架数据库上下文,您不应该这样做:

var loggedInMemberBookings = _apiDbContext.MedicalSolutionsBookings;
List<long> bookingIdsByLoggedInUser = new List<long>();

foreach (var booking in loggedInMemberBookings)
{
    if (booking.MemberNumber == loggedInMemberNumber)
    {
        bookingIdsByLoggedInUser.Add(booking.BookingId);
    }
}

这将强制代码遍历表中的每一行。正确的方法是使用 LINQ 查询。例如:

var bookingIdsByLoggedInUser = _apiDbContext.MedicalSolutionsBookings
    .Where(row => row.MemberNumber == loggedInMemberNumber)
    .ToList();

此版本使用LINQ Where operator,它将被实体框架转换为包含适当WHERE 子句的SQL,并将由数据库本地处理。这可以带来更好的性能,尤其是对于大型表。这也使用LINQ ToList operator 将查询“具体化”为内存中的项目列表。

对于你崩溃的部分,有一些问题。首先,BookingListDtoData 属性是一个IEnumerable,它没有Add 方法。其次,BookingListDto 使用的 Data 类与 3rd 方 API 返回的类不同,因此您需要将 3rd 方响应中的数据复制到您的 Data 类中。最后,您的Result&lt;&gt; 类提供了几个factory methods,这将是一种更简洁的方式来创建结果。

我认为通过考虑创建要返回的项目列表、从中创建 DTO、然后使用工厂方法从中创建结果来为您提供更好的服务。所以而不是:

            //This is where I want to create an object to store the correct bookings from the original response
            Result<BookingListDto> correctBookings = new Result<BookingListDto>();
            foreach (var responseBookingData in response.Response.Data)
            {
                foreach (var bookingId in bookingIdsByLoggedInUser)
                {
                    if (responseBookingData.Id == bookingId)
                    {
                        //This is where I fall apart, Data has no method to add or remove items
                        correctBookings.Response.Data.Add(responseBookingData);
                    }
                }
            }

您可以再次使用 LINQ 创建响应项列表,然后调用工厂方法创建结果,如下所示:

// first create the list of bookings to return
var bookings = response.Response.Data
    .Where(responseBookingData => bookingIdsByLoggedInUser.Any(id => id == responseBookingData.Id)
    .Select(responseBookingData => new Data { /* copy properties from resonseBookingData here */ })
    .ToList();
var dto = new BookingListDto { Data = bookings };
var response = Result<BookingListDto>.Ok(dto, HttpStatusCode.OK);

除了WhereToList 运算符之外,它还使用了LINQ AnySelect 运算符。

请注意,ToList 运算符返回一个List&lt;&gt;,它实现了IEnumerable&lt;&gt; 接口,因此被分配给BookingListDto.Data 属性。

【讨论】:

  • 当时我本来想回复你的,但是假期来了,我后来才回到这个问题上——你的帖子很有帮助,感谢你的详细回复。我希望你的 2021 年很棒:)
猜你喜欢
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多