匿名类型的笛卡尔积

时间:2016-11-22 14:21:05

标签: c# json linq

我正在研究代码,它将给出两种匿名类型的笛卡尔积。这两个匿名类型是从数据库生成的。

第一个匿名类型的代码:

 private IEnumerable<object> GetItem()
    {
        return _unitOfWork.GetRepository<Item>()
            .ListAll()
            .Select(x => new
            {
                itemId = x.Id,
                itemName = x.Name
            })
    }  

第二个匿名类型的代码:

private IEnumerable<object> GetVenue()
    {
        return _unitOfWork.GetRepository<Venue>()
            .ListAll()
            .Select(x => new
            {
                locationName = x.Address.City,
                venueId = x.VenueId,
                venueName = x.Name
            })
    }  

我有以下方法来获取数据并执行笛卡尔积并返回数据。

public object GetRestrictLookupInfo(IEnumerable<int> lookupCombinations)
    {
        IEnumerable<object> restrictList = new List<object>();
        if (lookupCombinations.Contains(1))
        {
            var tempProductProfileList = GetItem();
            restrictList = tempProductProfileList.AsEnumerable();
        }
        if (lookupCombinations.Contains(2))
        {
            var tempProductGroupList = GetVenue();
            restrictList = (from a in restrictList.AsEnumerable()
                            from b in tempProductGroupList.AsEnumerable()
                            select new { a, b });
        }
        return restrictList;
    }

我有控制器调用此方法并以json格式返回数据。

控制器代码

public HttpResponseMessage GetData(IEnumerable<int> lookupCombinations)
    {
        var lookupRestrictInfo = _sellerService.GetRestrictLookupInfo(lookupCombinations);
        return Request.CreateResponse(HttpStatusCode.OK, lookupRestrictInfo);
    }  

预期响应为: -

[  {  
     "itemId": 1,  
     "itemName": "Music",        
     "locationName": "Paris",  
     "venueId": 99,  
     "venueName": "Royal Festival Hall"  
}  ]  

我收到的回复是

[  {  
"a": {  
  "itemId": 1,  
  "itemName": "Music"        
},  
"b": {  
  "locationName": "Paris",  
  "venueId": 99,  
  "venueName": "Royal Festival Hall" }  }]

我无法获得预期的JSON字符串。

4 个答案:

答案 0 :(得分:0)

尝试创建一个简单的对象而不是嵌套:

select new { a.itemId, a.itemName, b.locationName }

答案 1 :(得分:0)

要在输出中生成单个项目,您需要创建一个名为匿名的新类型。由于您使用的是object而非实际类型,因此最快的方法是将它们转换为dynamic

var tempProductGroupList = GetVenue();
restrictList = (from a in restrictList.Cast<dynamic>()
                from b in tempProductGroupList.Cast<dynamic>()
                select new {
                    itemId = (int)a.itemId,  
                    itemName = (string)a.itemName,        
                    locationName = (string)b.locationName,  
                    venueId = (int)b.venueId,  
                    venueName = (string)b.venueName
                });

此代码与产生两个列表的代码紧密耦合,因为它假定知道动态传递给它的类型的字段名称。源数据结构的任何变化都必须跟随代码组合的变化。此外,它会使运行时检查失败,因此您需要非常小心这段代码。

答案 2 :(得分:0)

您应该从显示问题的最简单的代码开始;您上面的代码有很多复杂性可能(或可能不)与您的问题有关。这是关于操纵匿名类型?用LINQ做笛卡尔积?将object转换为JSON?

这是你可能正在寻找的一个可能的答案;请注意,您可以使用泛型而不是object来传递匿名类型。

namespace AnonymousTypes
{
    class Program
    {
        static string Serialize(object o)
        {
            var d = (dynamic)o;
            return d.ItemId.ToString() + d.ItemName + d.VenueId.ToString() + d.LocationName + d.VenueName;
        }
        static string GetData<T>(IEnumerable<T> result)
        {
            var retval = new StringBuilder();
            foreach (var r in result)
                retval.Append(Serialize(r));
            return retval.ToString();
        }
        static string GetRestrictLookupInfo()
        {
            var restrictList = new[] { new { Id = 1, Name = "Music" }, new { Id = 2, Name = "TV" } };
            var tempProductGroupList = new[] { new { LocationName = "Paris", Id = 99, Name = "Royal Festival Hall" } };
            var result = from item in restrictList
                         from venue in tempProductGroupList
                         select new
                         {
                             ItemId = item.Id,
                             ItemName = item.Name,
                             LocationName = venue.LocationName,
                             VenueId = venue.Id,
                             VenueName = venue.Name
                         };
            return GetData(result);
        }

        public static string GetData()
        {
            return GetRestrictLookupInfo();
        }

        static void Main(string[] args)
        {
            var result = GetData();
        }
    }
}

如果这不是你想要的,你可以从不使用匿名类型的代码开始,例如

namespace AnonymousTypes
{
    sealed class Item
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    sealed class Venue
    {
        public string LocationName { get; set; }
        public int Id { get; set; }
        public string Name { get; set; }
    }

    sealed class ItemAndVenue
    {
        public int ItemId { get; set; }
        public string ItemName { get; set; }
        public string LocationName { get; set; }
        public int VenueId { get; set; }
        public string VenueName { get; set; }
    }

    class Program
    {
        static IEnumerable<Item> GetItem()
        {
            return new[] { new Item { Id = 1, Name = "Music" } };
        }

        static IEnumerable<Venue> GetVenue()
        {
            return new[] { new Venue { LocationName = "Paris", Id = 99, Name = "Royal Festival Hall" } };
        }

        static IEnumerable<ItemAndVenue> GetRestrictLookupInfo()
        {
            var restrictList = GetItem();
            var tempProductGroupList = GetVenue();
            var result = from item in restrictList
                    from venue in tempProductGroupList
                    select new ItemAndVenue
                    {
                        ItemId = item.Id,
                        ItemName = item.Name,
                        LocationName = venue.LocationName,
                        VenueId = venue.Id,
                        VenueName = venue.Name
                    };
            return result;
        }

        static string GetData()
        {
            var v = GetRestrictLookupInfo().First();
            return v.ItemId.ToString() + v.ItemName + v.VenueId.ToString() + v.LocationName + v.VenueName;
        }

        static void Main(string[] args)
        {
            var result = GetData();
        }
    }
}

答案 3 :(得分:0)

喜欢选项:

public object GetRestrictLookupInfo(IEnumerable<int> lookupCombinations)
{
    List<Dictionary<string, object>> result = new List<Dictionary<string, object>>();
    if (lookupCombinations.Contains(1))
    {
        var tmp = _unitOfWork.GetRepository<Item>()
                             .ListAll()
                             .Select(x => new
                             {
                                 itemId = x.Id,
                                 itemName = x.Name
                             })
                             .Select(x => 
                             {
                                 var dic = new Dictionary<string, object>();

                                 dic.Add(nameof(x.itemId), x.itemId);
                                 dic.Add(nameof(x.itemName), x.itemName);

                                 return dic;
                             });

        result.AddRange(tmp);
    }
    if (lookupCombinations.Contains(2))
    {
        var tmp = _unitOfWork.GetRepository<Venue>()
                             .ListAll()
                             .Select(x => new
                             {
                                 locationName = x.Address.City,
                                 venueId = x.VenueId,
                                 venueName = x.Name
                             })
                             .Select(x => 
                             {
                                 var dic = new Dictionary<string, object>();

                                 dic.Add(nameof(x.locationName), x.locationName);
                                 dic.Add(nameof(x.venueId), x.venueId);
                                 dic.Add(nameof(x.venueName), x.venueName);

                                 return dic;
                             });

        result = result.SelectMany(r => tmp.Select(t => r.Concat(t)));
    }

    return result;
}

看起来有点神奇。我使用字典而不是对象。它可以以更清晰的方式制作(提取少数方法),但这个想法应该是明确的。

然后,在序列化期间,它将根据您的需要显示。

相关问题