【问题标题】:c# using Linq to project an array within an array onto a new array?c# 使用 Linq 将数组中的数组投影到新数组上?
【发布时间】:2020-06-04 23:28:17
【问题描述】:

我正在使用 .NET Core 并构建 API。我有传入的 JSON,我将其映射到 C# 对象,在大多数情况下,JSON 非常简单,除了一个部分可能在数组中包含一个数组,见下文:

"marketing_preferences": [
  {
    "channel": "EDM",
    "opt_in": false,
    "valid_from_date": "2020-05-30T07:07:53.723Z",
    "content_type_preferences": [
      {
        "type": "CAT",
        "opt_in": false,
        "valid_from_date": "2020-05-30T07:07:53.724Z"
      },
      {
        "type": "TAC",
        "opt_in": true,
        "valid_from_date": "2020-05-30T07:07:53.724Z"
      }
    ]
  },
  {
    "channel": "SMS",
    "opt_in": true,
    "valid_from_date": "2020-05-30T07:07:53.724Z",
    "content_type_preferences": []
  },
  {
    "channel": "SM",
    "opt_in": true,
    "valid_from_date": "2020-05-30T07:07:53.724Z",
    "content_type_preferences": []
  }
]

营销偏好可能(但可能不)包含一个或多个 content_type_preferences。所以marketing_preferences 是一个数组,content_type_preferences 是该数组中的一个可选数组。在我的代码中映射或预测营销偏好非常简单:

    customer.MarketingPreferences = source.RequestCustomer.MarketingPreferences
        .Select(x => new MarketingPreferences()
        {
            ChannelId = x.Channel,
            OptIn = x.OptIn,
            ValidFromDate = x.ValidFromDate,
            UpdatedBy = Functions.DbUser,
            CreatedDate = DateTime.UtcNow,
            UpdatedDate = DateTime.UtcNow,
            UpdatingStore = null // Not passed by API
        })
        .ToList();

但是,我对将 content_type_preferences 投影到其等效对象的语法有点卡住了。以下是我要投影的类:

public partial class MarketingPreferences
{
    public MarketingPreferences()
    {
        ContentTypePreferences = new HashSet<ContentTypePreferences>();
    }

    public Guid CustomerInternalId { get; set; }
    public string ChannelId { get; set; }
    public bool? OptIn { get; set; }
    public DateTime? ValidFromDate { get; set; }
    public string UpdatedBy { get; set; }
    public DateTime? CreatedDate { get; set; }
    public DateTime? UpdatedDate { get; set; }
    public string UpdatingStore { get; set; }

    public virtual Customer CustomerInternal { get; set; }
    public virtual ICollection<ContentTypePreferences> ContentTypePreferences { get; set; }
}

public partial class ContentTypePreferences
{
    public Guid CustomerInternalId { get; set; }
    public string ChannelId { get; set; }
    public string TypeId { get; set; }
    public bool? OptIn { get; set; }
    public DateTime? CreatedDate { get; set; }
    public DateTime? UpdatedDate { get; set; }
    public DateTime? ValidFromDate { get; set; }
    public string UpdatedBy { get; set; }
    public string UpdatingStore { get; set; }

    public virtual MarketingPreferences C { get; set; }
    public virtual Customer CustomerInternal { get; set; }
}

我确实开始恢复到一种笨拙的方式来做这件事,但我真的不满意,我更愿意尝试找到 LINQ 式的方式来实现以下目标:

    foreach (var marketingPrefs in source.RequestCustomer.MarketingPreferences)
    {
        if (marketingPrefs.ContentTypePreferences.Length > 0)
        {
            Console.WriteLine($"marketing preference: {marketingPrefs.Channel}");
            foreach (var contentPrefs in marketingPrefs.ContentTypePreferences)
            {
                Console.WriteLine($"content preference: {contentPrefs.Type}");
                customer.ContentTypePreferences.Add(new ContentTypePreferences
                {
                    TypeId = contentPrefs.Type,
                    OptIn = contentPrefs.OptIn,
                    ValidFromDate = contentPrefs.ValidFromDate
                });
            }
        }
    }

【问题讨论】:

  • SelectMany 可以工作吗?
  • 您好,mjwills,您能否举例说明您的意思?
  • 这能回答你的问题吗? Flatten an Array in C#

标签: c# arrays entity-framework linq


【解决方案1】:

简单的SelectMany 应该足以展平集合:

customer.ContentTypePreferences = source.RequestCustomer.MarketingPreferences
    .SelectMany(mp => mp.ContentTypePreferences)
    .Select(contentPrefs => new ContentTypePreferences
            {
                TypeId = contentPrefs.Type,
                OptIn = contentPrefs.OptIn,
                ValidFromDate = contentPrefs.ValidFromDate
            })
    .ToList();

【讨论】:

    【解决方案2】:

    我确实找到了使用以下方法解决此问题的方法。

        customer.MarketingPreferences = source.RequestCustomer.MarketingPreferences
            .Select(x => new MarketingPreferences()
            {
                ChannelId = x.Channel,
                OptIn = x.OptIn,
                ValidFromDate = x.ValidFromDate,
                UpdatedBy = Functions.DbUser,
                CreatedDate = DateTime.UtcNow,
                UpdatedDate = DateTime.UtcNow,
                ContentTypePreferences = (from c in x.ContentTypePreferences
                        select new ContentTypePreferences
                        {
                            TypeId = c.Type,
                            OptIn = c.OptIn,
                            ValidFromDate = c.ValidFromDate,
                            ChannelId = x.Channel // Should inherit parent marketing preference channel
                        }).ToList(),
                UpdatingStore = null // Not passed by API
            })
            .ToList();
    

    我很欣赏其他答案,但意识到仅仅展平可能还不够,因为每个 ContentTypePreference 的 ChannelId 没有通过 POST JSON 传递,而是从该 ContentTypePreference 的父 MarketingTypePreference 派生(例如EMAIL 将有一个 EMAIL 的通道 ID),所以上面的解决方案让我在为实体框架创建每个新的 ContentTypePreferences 时注入它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-19
      • 1970-01-01
      • 1970-01-01
      • 2019-01-13
      • 2014-03-10
      • 2021-09-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多