I have DTOs like this
public class Obj1
{
public string a1 { get; set; };
public Obj2[] a2 { get; set; };
}
public class Obj2
{
public string b1 { get; set; };
public Obj3[] b2 { get; set; };
}
public class Obj3
{
public string Key { get; set; };
}
So, the object will be like
Obj1 o = new Obj1
{
a1="a";
a2=new[]
{
new Obj2
{
b1="b";
b2=new[]
{
new Obj3
{
Key="c";
}
}
}
}
}
I have Obj1. How can I group it in the form of dictionary of type
IDictionary<string, IEnumerable<Obj2>>
where Key is in Obj3.
I tried using GroupBy but did not get the relevant result.
If I understand the end goal - co combine all Obj2 by all child Obj3.Key and after fixing the code to make it compile you can use SelectMany into intermediate data structure with aggregation with GroupBy:
var dictionary = o.a2
.SelectMany(o2 => o2.b3.Select(o3 => (o3.Key, o2)))
.GroupBy(t => t.Key)
.ToDictionary(g => g.Key, g => g.ToList());
Im not quite sure, but your class "obj2" instead of having 2 properties, you can make it with one property of Dictionary with a string key and Ienumerable value, so your variable could look like this.
Dictionary<string, Dictionary<string, Ienumerable>> and you can add "obj3" as a value or key.
Related
JSON parsed to Web API Post Call (Body)
{
"Name1": "Value1",
"Name2": "Value2",
"Name3": "Value3",
"Name4": "Value4"
}
Lets call this object NameValueObject
public class NameValueObject
{
public Name1 { get; set; }
public Name2 { get; set; }
public Name3 { get; set; }
public Name4 { get; set; }
}
What I would like to see is to be able to parse the json object and convert it into a list
public async Task<List<NameValueObject>> EvaluateJson ([FromBody] NameValueObject request)
{
string serializerequest = JsonConvert.SerializeObject(request);
//What do i next , I just to want to get a list of the values sent through the json object
}
you can create List< NameValueObject > objects
var json= JsonConvert.Serialize(request);
List<NameValueObject> objects = JsonConvert.DeserializeObject<Dictionary<string, string>>(json)
.Select(i => new NameValueObject {Name=i.Key, Value=i.Value} )
.ToList();
or just list of values
var json= JsonConvert.Serialize(request);
List<string> values=JsonConvert.DeserializeObject<Dictionary<string, string>>(json)
.Select(i => i.Value )
.ToList();
if you want List< NameValueObject > , you will have to create this class
public class NameValueObject
{
public string Name { get; set; }
public string Value { get; set; }
}
or I would prefer this
public async Task<List<NameValueObject>> EvaluateJson ([FromBody] JObject jsonObject)
{
return jsonObject.Properties()
.Select ( i => new NameValueObject {
Name = i.Name, Value = (string) i.Value }).ToList();
}
or just list of values
List<string> Values = jsonObject.Properties().Select( i => (string) i.Value ).ToList();
You can get all the values of your properties in the NameValueObject by using Reflection and Linq like this:
var values = nameValueObject.GetType().GetProperties().Select(v => v.GetValue(nameValueObject));
If you would like to get both the name of the property and the value you can create a dictionary like this:
var dictionary = nameValueObject.GetType().GetProperties().ToDictionary(v => v.Name, v => v.GetValue(nameValueObject));
The Console project code sample below is analogous to my code; irl there is a more complexity but the problem I am having is demonstrated adequately. I cannot understand why the linq select in the Demo method returns a null when one side seems of the where<> clause seems to match the expression used in the foreach loop to populate the other side of the where<> clause.
I have tried loads of different permutations of the same code, but whatever I do I am working with a null thisOrder; I can't seem to get past that to be able to work with anything.
What am I missing; why does my where clause not return the orders in the inner dictionary of the orders dictionary?
using System;
using System.Collections.Generic;
using System.Linq;
namespace ShowTest
{
public class Depot
{
public string Name { get; set; }
public Dictionary<Order, Dictionary<int, OrderLine>> Orders { get; set; } = new Dictionary<Order, Dictionary<int, OrderLine>>(new OrderEqualityComparer());
}
public class Order
{
public string Reference { get; set; }
public DateTime DepotDate { get; set; }
}
#region comparer
public class OrderEqualityComparer : IEqualityComparer<Order>
{
public bool Equals(Order x, Order y)
{
return (x.Reference == y.Reference);
}
public int GetHashCode(Order obj)
{
return (obj.Reference.GetHashCode());
}
}
#endregion
public class OrderLine
{
public int Qty { get; set; }
public string ExternalRef { get; set; }
}
public class Demo
{
public static void Main()
{
#region Setting up values
Order order = new Order { DepotDate = DateTime.Parse("15/01/2010"), Reference = "myOrderRef" };
OrderLine orderLine1 = new OrderLine { ExternalRef = "Foo", Qty = 4 };
OrderLine orderLine2 = new OrderLine { ExternalRef = "Bar", Qty = 8 };
var orderLines = new Dictionary<int, OrderLine>();
orderLines.Add(1, orderLine1);
orderLines.Add(2, orderLine2);
var orders = new Dictionary<Order, Dictionary<int, OrderLine>>();
orders.Add(order, orderLines);
Depot myDepot = new Depot { Name = "Funhouse", Orders = orders };
#endregion
foreach (string oRef in myDepot.Orders.Select(l => l.Key.Reference))
{
//for each order reference, there is an order containing many order lines. So, first we get the relevant order
var thisOrder = (from l in myDepot.Orders
where l.Key.Reference == oRef
select l.Value.Values) as Dictionary<int, OrderLine>;
if (thisOrder == null) { Console.WriteLine("Why is thisOrder null when the search criterion was retrieved from the order itself?"); }
else { Console.WriteLine("Hooray, the damnable thing has contents!"); }
}
}
}
}
Because you're interpreting thisOrder as the wrong type:
as Dictionary<int, OrderLine>
Since the result of the expression is not a Dictionary<int, OrderLine>, the result of trying to cast it to one is null. The result is a collection, and not even of Dictionary<int, OrderLine> objects but of Dictionary<int, OrderLine>.ValueCollection objects. (A collection which contains one element, but a collection nonetheless.)
You can select from that collection. For example, if what you want is a Dictionary<int, OrderLine>:
var thisOrder = (from l in myDepot.Orders
where l.Key.Reference == oRef
select l.Value).FirstOrDefault();
Overall the main point is that your querying works just fine, but you're telling the system to use the wrong types.
Is it possible to select a single object and populate a containing IEnumerable property with a single Lambda expression?
Something like this:
var someViewModel = _repository.Table.Where(x => x.Id == someId)
.Select(new ListViewModel(){
GroupId = x.Group.Id,
GroupTitle = x.Group.Title
List = ?? // Select new SubViewModel and add it to IEnumerable<SubViewModel>
})
The result I'm after is a new object (ListViewModel in this case) that contains 3 properties. "List" being a collection of newly selected objects.
Is this possible? Am I coming at this from the wrong angle?
Thanks!
Update:
Let me try again :) Keep in mind that my naming is fictional here. Given the following two classes I would like to construct a DB query using a Lambda expression which creates a single "ListViewModel" that contains a collection of "SubViewModel". Does this help clarify?
public class SubViewModel
{
public int Id { get; set; }
public string Title { get; set; }
}
public class ListViewModel
{
public int GroupId { get; set; }
public string GroupTitle { get; set; }
public IEnumerable<SubViewModel> List { get; set; }
}
I'm not sure if I understand your question correctly but here is what I am thinking, you need to create a new IEnumberable and add the item to that collection.
var someViewModel = _repository.Table.Where(x => x.Id == someId)
.Select(new ListViewModel()
{
GroupId = x.Group.Id,
GroupTitle = x.Group.Title
List = new List<SubViewModel> { new SubViewModel(x) }
});
I want to populate a list where a value in the object is in another list I've already populated. Please see below:
//Populate first object
List<Object1> listObject1 = da.dbsetObject1.Where(p=>p.ID.Equals(SomeID)).ToList();
//Populate second object - what I want to do but can't figure out
List<Object2> listObject2 = da.dbsetObject2.Where(p=>p.ID.Contains(listObject1.Object1ID)).ToList();
I know contains doesn't work but I want to basically populate listObject2 with all the values that have a matching Object1ID. In a sql table this would be a foreign key relationship.
Then join the two lists:
var results = from l2 in listObject2
join l1 in listObject1 on l2.ID equals l1.Object1ID
select new{anonymous type}
EDIT
Based on updated information in comments
var lstObject1 = listObject1.Select(item -> item.ObjectId).ToArray();
List<Object2> listObject2 = da.dbsetObject2.Where(p=> lstObject1.Contains(p.ObjectId)).ToList();
Original
Question is not clear from the code
Assuming, you cant p.ID in List, resulting query is
List<Object2> listObject2 = da.dbsetObject2.Where(p=> listObject1.Contains(p.ID)).ToList();
Try something like this.
//Populate first object
List<Object1> listObject1 = da.dbsetObject1.Where(p => p.ID.Equals(SomeID)).ToList();
//Populate second object - what I want to do but can't figure out
List<Object2> listObject2 = da.dbsetObject2.Where(p => listObject1.Any(q => q.ID == p.foreignID)).ToList();
UPDATE
void SomeMethod(){
var arr = new Object1[]{
new Object1{Name="n1",ID=1},
new Object1{Name="n2",ID=2},
new Object1{Name="n3",ID=3},
new Object1{Name="n4",ID=4}
};
var arr2 = new Object2[]{
new Object2{Name="o1", Ref=1},
new Object2{Name="o2", Ref=2},
new Object2{Name="o3", Ref=1},
new Object2{Name="o4", Ref=2},
new Object2{Name="o5", Ref=5},
new Object2{Name="o6", Ref=3},
new Object2{Name="o7", Ref=5}
};
List<Object1> listObject1 = arr.Where(p => p.ID == 1 || p.ID == 2).ToList();
List<Object2> listObject2 = arr2.Where(p =>listObject1.Any(q => p.Ref == q.ID)).ToList();
}
class Object1
{
public string Name;
public int ID;
}
class Object2
{
public string Name;
public int Ref;
}
I figured out the best approach for what I am trying to do. Here is the code I needed:
var NewObject = da.dbsetObject1.Include("listObject2").ToList();
Then I can use NewObject as a list, and when I need an Object2 value associated with a particular Object1 value I can grab it.
Here are the classes:
public class Object1
{
[Key]
public int Object1ID { get; set; }
.....
public int Object2ID { get; set; }
public List<Object2> listObject2 { get; set; }
}
public class Object2
{
[Key]
public int Object2ID { get; set; }
.....
public int Object1ID { get; set; }
public Object2 myObject2 { get; set; }
}
Thanks everyone for the help! I wish a lambda expression had worked it looks a lot cleaner especially once I start adding more includes.
Ugh, how do I explain this one... Probably a simple question but my mind is fried.
Suppose I have this class:
public class NestedObject
{
public string NestedName { get; set; }
public int NestedIntValue { get; set; }
public decimal NestedDecimalValue { get; set; }
}
public class SomeBigExternalDTO
{
public int Id { get; set; }
public int UserId { get; set; }
public int SomeIntValue { get; set; }
public long SomeLongValue { get; set; }
public decimal SomeDecimalValue { get; set; }
public string SomeStringValue { get; set; }
public NestedObject SomeNestedObject { get; set; }
// ... thousands more of these properties... inherited code
}
And the class I'd like to populate is here:
public class MyResult
{
public int UserId { get; set; } // user id from above object
public string ResultValue { get; set; } // one of the value fields from above with .ToString() executed on it
}
What I'd like to do is create a helper to return the property values (a cross section is the best way I could describe it I guess) of all instances in a list of this object:
var foo = new List<SomeBigExternalDTO>();
foo = GetMyListOfSomeBigExternalDTO();
public static List<MyResult> AwesomeHelper(List<SomeBigExternalDTO> input, SearchableProperty thePropertyIWant)
{
// some magic needs to happen here...
}
The tricky part here is I want to dynamically pass in the property based on a link selector (I have no clue how to do this):
var output = AwesomeHelper(GetMyListOfSomeBigExternalDTO(), x => x.SomeIntValue);
var output2 = AwesomeHelper(GetMyListOfSomeBigExternalDTO(), x => x.SomeNestedObject.NestedIntValue);
And this should return a list of MyResult objects with the UserId and SomeIntValue.ToString() corresponding to each item in the input list.
Wow, I really hope this makes sense. Please let me know if this is not clear I'll provide more details. I'm really hoping this is something baked into the libraries that I've overlooked.
Any ideas on I'd accomplish this?
You could implement it as an extension method:
public static IEnumerable<MyResult> AwesomeHelper(this IEnumerable<SomeBigExternalDTO> input,
Func<SomeBigExternalDTO, int> intMapper)
{
foreach (var item in input)
yield return new MyResult()
{
UserId = item.UserId,
ResultValue = intMapper(item)
};
}
Now you can use it like this:
var output = GetMyListOfSomeBigExternalDTO().AwesomeHelper( x => x.SomeIntValue);
var output2 = GetMyListOfSomeBigExternalDTO().AwesomeHelper( x => x.SomeNestedObject.NestedIntValue);
Having said that - dont' do that - it somehow looks like you are reinventing what Linq already offers you, you can do just the same using only Linq:
var output = GetMyListOfSomeBigExternalDTO().Select( x=> new MyResult()
{
UserId = item.UserId,
ResultValue = x.SomeIntValue
});
var output2 = GetMyListOfSomeBigExternalDTO().Select( x=> new MyResult()
{
UserId = item.UserId,
ResultValue = x.SomeNestedObject.NestedIntValue
});
Often when trying to create a general purpose list operator you end up reimplementing what LINQ already offers you.
Here's the LINQ code for what you're after (without an AwesomeHelper function):
var results = list.Select(l => new MyResult()
{
UserId = l.UserId,
ResultValue = l.SomeDecimalValue.ToString()
}).ToList();
Fairly simple.
If you want to have an AwesomeHelper function as you requested then it looks like this:
public static List<MyResult> AwesomeHelper(
List<SomeBigExternalDTO> input,
Func<SomeBigExternalDTO, object> selector)
{
return input
.Select(i => new MyResult()
{
UserId = i.UserId,
ResultValue = selector(i).ToString()
})
.ToList();
}
And the calling code look like this:
var results = AwesomeHelper(list, x => x.SomeIntValue);
To me, though, this is now less readable than the LINQ option. Now there is some magic being wrought and it's hard to work out what.
I have an alternative that will give you the best of both worlds.
First, define an extension method called ToMyResult that maps a single SomeBigExternalDTO instance into a single MyResult with a field selector, like this:
public static class AwesomeHelperEx
{
public static MyResult ToMyResult(
this SomeBigExternalDTO input,
Func<SomeBigExternalDTO, object> selector)
{
return new MyResult()
{
UserId = input.UserId,
ResultValue = selector(input).ToString()
};
}
}
Now the calling code is crystal clear, flexible and concise. Here it is:
var results = (
from item in list
select item.ToMyResult(x => x.SomeLongValue)
).ToList();
I hope this helps.