Map parts of an aggregate to a List<T> - c#

Let us say we have a simple business object:
class SimpleBO
{
public string Field1{get;set;}
public string Field2{get;set;}
}
Also we have a complex Aggregate like that:
class ComplexBO
{
public SimpleBO SimpleBOField {get;set}
public List<SomeClass> ObjectList {get;set;}
public SomeClass Object {get;set;}
}
SomeClass itself has a reference of SimpleBO:
class SomeClass
{
public SimpleBO SimpleBOField {get;set}
}
Now in some part of my program I want to get a list of all distinct simple objects met inside a certain aggreggate. We are using automapper heavily but I did not manage to map it so far. May be a LINQ query is a better option? How would you solve this?

Assuming what you have is:
ComplexBO aggregate = ...
then you should just need:
var objects = aggregate.ObjectList.Select(x => x.SimpleBOField).Concat(
new[] {aggregate.SimpleBOField, aggregate.Object.SimpleBOField }
).Distinct().ToList();
This will give you the distinct object references; if you need distinct value pairs, then either override Equals()/GetHashCode(), or cheat:
var objects = aggregate.ObjectList.Select(x => x.SimpleBOField).Concat(
new[] {aggregate.SimpleBOField, aggregate.Object.SimpleBOField }
).Select(
x => new {x.SimpleBOField.Field1, x.SimpleBOField.Field2}
).Distinct().Select(
x => new SimpleBO {Field1 = x.Field1, Field2 = x.Field2}
).ToList();

Related

How to map a list of objects to an object that contains multiple lists?

I am using automapper 9.0.0.
My situation is as follows. I have a list of items which are all instances of an abstract base class, let's call it BaseClass. There are 2 classes that inherit that class, let's call those Bar1Class and Bar2Class.
I want to map a list of BaseClass to an object that contains 2 lists. One list is a DTO for the Bar1Class objects from the list, and the 2nd one is for the Bar2Class objects from the list:
List<BaseClass> items = GetItems();
var dto = Mapper.Map<FooResponseModel>(items);
The hierarchy is as follows:
// Response models
public class FooResponseModel
{
public IEnumerable<Bar1Model> Bar1Models {get;set;}
public IEnumerable<Bar2Model> Bar2Models {get;set;}
}
public class Bar1Model
{
public string MyString {get;set;}
public int MyInt {get;set;}
}
public class Bar2Model
{
public string MyString {get;set;}
public bool MyBool {get;set;}
}
public abstract class BaseClass
{
public string MyString {get;set;}
}
public class Bar1Class : BaseClass
{
public int MyInt {get;set;}
}
public class Bar2Class : BaseClass
{
public bool MyBool {get;set;}
}
How would I set this up?
Using the CreateMap<BaseClass, FooResponseModel>() doesn't really work because I can't divide the collections. Doing something like CreateMap<Bar1Class, Bar1Model>() would allow me to map the classes itself, but not allow me to set up the lists.
Thanks!
Edit:
I would map it by hand like this now, because i dont know how to map the upper object correctly. I would of course add CreateMap<Bar1Class, Bar1Model>() and such beforehand.
var dto = new FooResponseModel
{
Bar1Models = items
.Where(x => x is Bar1Class)
.Cast<Bar1Class>()
.Select(x => Mapper.Map<Bar1Model>()),
Bar2Models = items.
.Where(x => x is Bar2Class)
.Cast<Bar2Class>()
.Select(x => Mapper.Map<Bar2Model>())
}
Create two maps between source classes and destination classes. Then, add mapping from a sequence of BaseClass to FooResponseModel and point AutoMapper how to populate Bar1Models and Bar2Models properties.
CreateMap<Bar1Class, Bar1Model>();
CreateMap<Bar2Class, Bar2Model>();
CreateMap<IEnumerable<BaseClass>, FooResponseModel>()
.ForMember(d => d.Bar1Models, o => o.MapFrom(s => s.Where(b => b is Bar1Class)))
.ForMember(d => d.Bar2Models, o => o.MapFrom(s => s.Where(b => b is Bar2Class)));

Converting a distinct list to dictionary not working

I'm trying to convert a list of objects to a dictionary using the following code:
var MyDictionary = MyList.Distinct().ToDictionary(i => i.ObjectId, i => i);
I know that a dictionary should not contain duplicate elements, hence the .Distinct(). Yet I still get the following Exception whenever there's a duplicate element:
An item with the same key has already been added.
MyList is a list of MyObject that looks like this:
public class MyObject{
public string ObjectId { get; set; }
public string FName { get; set; }
public string LName { get; set; }
}
Is there a better way to create a dictionary from a list of objects ? or am I doing something wrong?
If you want to compare on the ObjectId, you'll need to pass in a custom comparer to .Distinct(). You can do so like this:
class MyObjectComparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.ObjectId == y.ObjectId;
}
public int GetHashCode(MyObject obj)
{
return obj.ObjectId.GetHashCode();
}
}
var MyDictionary = MyList
.Distinct(new MyObjectComparer())
.ToDictionary(i => i.ObjectId, i => i);
You could use Group by and then select first from the List as below:
var MyDictionary = MyList.GroupBy(i => i.ObjectId, i => i).ToDictionary(i => i.Key, i => i.First());
Distinct works using the objects built in Equals and GetHashCode methods by default but your dictionary works only over the id. You need to pass in a IEqualityComparer in to distinct that does the comparison on Id to test if items are equal or make MyObject implment Equals and GetHashCode and have that compare on the Id.

Is there a way to simplify initializing Linq new object initialization?

I find that I am repeating a lot of new object initialization code in Linq queries, for example when creating different overloaded methods that use the same query structure.
var result = ItemResponses
.GroupBy(ir => ir.ItemID)
.Select(
grouped => new
{
ItemID = grouped.Key,
Average = (double)grouped.Average(g => g.OptionValue),
...etc. lots of properties, similar structure across lots of methods...
...Would really love to be able to write this code once somewhere...
}
);
At first I thought using constructors might be one way of doing it, something along these lines:
var result = ItemResponses
.GroupBy(ir => ir.ItemID)
.Select(grouped => new TestClass(grouped) //or anonymous type
);
public class TestClass
{
public int ItemID { get; set; }
public double Average { get; set; }
public TestClass() {}
public TestClass(IGrouping<int, ItemRespons> values)
{
ItemID = values.Key;
Average = values.Average(g => g.OptionValue);
}
}
But I see that Linq (to Entities at least) only allows parameterless constructors and initializers. So this approach doesn't seem to work.
Is there another way I can achieve simplifying this type of repetive code, and only having it in one place?
Use a delegate:
Func<IQueryable<ItemResponse>,IEnumerable<TestClass>> SelectResult = q =>
q.GroupBy(ir => ir.ItemID)
.Select(
grouped => new TestClass
{
ItemID = grouped.Key,
Average = (double)grouped.Average(g => g.OptionValue),
...
});
Then you can use it like this:
var result = SelectResult(ctx.ItemResponse);
It's even better to make it a extension method of course:
public static class Extensions
{
public static IEnumerable<TestClass> SelectResult(this IQueryable<ItemResponse> q)
{
return q.GroupBy(ir => ...)
}
}
And use it like this:
var result = ctx.ItemResponses.SelectResult();
It's not possible for anonymous type projections because there is no way to define a typed result, except some non generic type like dynamic, object or IQueryable, but then you'll have problem consuming it.
However it is possible to reuse projections to a custom types (like your sample TestClass). But instead of constructor, you have to put the code in a expression returning method.
For instance, instead of this
public TestClass(IGrouping<int, ItemResponse> values)
{
ItemID = values.Key;
Average = values.Average(g => g.OptionValue);
// ...etc. lots of properties
}
you could use something like this
static Expression<Func<IGrouping<int, ItemResponse>, TestClass>> ToTestClass()
{
return values => new TestClass
{
ItemID = values.Key,
Average = values.Average(g => g.OptionValue)
// ...etc. lots of properties
};
}
and the sample query would be
var result = ItemResponses
.GroupBy(ir => ir.ItemID)
.Select(ToTestClass());

Sort ArrayList with custom comparison

I am trying to sort an ArrayList using c#. When the ArrayList contains comparable objects, it is possible to sort with using list.Sort() but I need to sort an ArrayList which contains non-comparable objects. For example, let's say the object is Ring and it has an attribute property Price. Then I need to sort the ArrayList to the price order. If is is possible to select ascending or descending that will more helpful. Thank You!
Blockquote
arrAtdMon = **(ArrayList)**hashTb[unixMon];
if (arrAtdMon != null)
monCount = arrAtdMon.Count;
int[] arrayMax = { monCount, tueCount, wedCount, thuCount, friCount };
int maxValue = arrayMax.Max();
KidAttendance valMon = null;
string monTagName = string.Empty;
Blockquote
above array list is to be sorted it self.
You can do this by implementing IComparer interface:-
public class Ring : IComparer
{
public decimal Price { get; set; }
public int Compare(object x, object y)
{
return ((Ring)x).Price.CompareTo(((Ring)y).Price);
}
}
Working Fiddle.
First, you really should be using the List<T> class, not ArrayList. Doing so wouldn't solve your problem, but it would make the code less fragile and more easy to maintain.
As for the specific question, you want to do something like this…
Assume:
class Ring { public decimal Price { get; set; } }
Then:
ArrayList list = ...; // Initialized as some collection of Ring instances
list.Sort(Comparer.Create((r1, r2) => r1.Price.CompareTo(r2.Price)));
This creates a new Comparer instance using the Comparison<T> of (r1, r2) => r1.Price.CompareTo(r2.Price). That is, for each pair of objects being compared, compare the price of the first with the price of the second.
Assuming that these objects share a base class or an interface with the price property you should be able to do something like this:
// Base class with price property, could also be an shared interface
public abstract class Product
{
public decimal Price{get;set;}
}
public class Ring : Product
{
}
public class Bag : Product
{
}
// Some test data
var myUnsortedArray = new Product[]{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArray.OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArray.OrderByDescending(p => p.Price).ToArray();
UPDATE
I just realised that the question is about ArrayLists and have the changed solution below:
// Some test data
var myUnsortedArrayList = new ArrayList{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArrayList.OfType<Product>().OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArrayList.OfType<Product>().OrderByDescending(p => p.Price).ToArray();
To sort an set of objects, the object needs to be Comparable and you can set up the comparison you'd like in the CompareTo() method:
IComparable information here

Using LINQ, select list of objects inside another list of objects

public class ClassA
{
public string MyString {get; set;}
}
public class ClassB
{
public List<ClassA> MyObjects {get; set;}
}
List<ClassB> classBList = new List<ClassB>();
var results = (from i in classBList select i.MyObjects).Distinct();
I want a distinct list of all the ClassA objects in the classBList. How do I go about this using LINQ? I'm thinking about a nested query, but couldn't quite figure it out. Any help is very appreciated.
You're trying to select multiple result objects for each ClassB object in the original list.
Therefore, you're looking for the SelectMany extension method:
var results = classBList.SelectMany(b => b.MyObjects).Distinct();
If you want to use query expressions, you'll need to use two from clauses:
var results = (from b in classBList from a in b.MyObjects select a).Distinct();
You want to use IEnumerable.SelectMany() Extension Method to flatten the hierarchy:
var result = classBList.SelectMany(b => b.MyObjects).Distinct();

Categories