Get new and existing items between lists - c#

First we pull in new alerts and deserialize them. Now I only care about 2 properties that need to be compared: CommandID and AlertID, all others can be ignored so I create a new object which I assumed would have been easier to compare the results. All other properties become null.
List<AlertModel> alerts = JsonConvert.DeserializeObject<List<AlertModel>>(json)
.Select(x => new AlertModel() { CommandID = x.CommandID, AlertID = x.AlertID }).ToList();
Now I want to find new alerts that don't already exist
List<AlertModel> newAlerts = alerts.Except(currentAlerts).ToList();
Next we pull what alerts already exist.
List<AlertModel> existingAlerts = currentAlerts.Intersect(alerts).ToList();
Now we store new and existing alerts.
currentAlerts.Clear();
currentAlerts.AddRange(newAlerts);
currentAlerts.AddRange(existingAlerts);
1st run alerts contains 1 item newAlerts contains 1 item and existingAlerts contains 0 as they should.
2nd run through isn't what I was expecting.
alerts contains 1 as it should.
newAlerts contains 1 and this should be 0. currentAlerts contains the exact same CommandID and AlertID as in alerts
existingAlerts contains 0 and this should be 1 since the same CommandID and AlertID exists in currentAlerts and alerts.
Not sure what i'm missing here and maybe there is a better way to do this.

Replace this code:
List<AlertModel> newAlerts = alerts.Except(currentAlerts).ToList();
Whit this:
List<AlertModel> newAlerts = alerts.Where(x => !currentAlerts.Any(y => y.CommandID == x.CommandID && y.AlertID == x.AlertID)).ToList();
The issue is that your alerts list contains new elements (new AlertModel() { CommandID = x.CommandID, AlertID = x.AlertID }). This is a reference problem.
Animal a = new Animal { Color = "Red" };
Animal b = new Animal { Color = "Red" };
a == b; // This returns false
Alternatively you can override Equals method in you class. To do this in your class:
public class AlertModel {
// Some things
public override bool Equals(object model) {
return model != null && CommandID == model.CommandId && AlertID == model.AlertID;
}
}

Override Equals and GetHashCode in your AlertModel class. Return a constant value in GetHashCode() (e.g. -1) if you want to force to call your Equals method.
public override bool Equals(object obj)
{
var that = obj as AlertModel;
return that != null && that.AlertId == this.AlertId && that.CommandId == this.CommandId;
}
public override int GetHashCode()
{
int hash = 13;
return (this.AlertId.GetHashCode() * this.CommandID.GetHashCode()) ^ hash;
}

var uniqueAlerts = alerts.Where(a=> !currentAlerts.Any(c=> c.CommandID == a.CommandID && c.AlertID== a.AlertID));

Related

Some values in LINQ Query Statement aren't saved correctly to class with subsonic 3

I am developing a MVC 3 Application which uses Subsonic 3 for accessing the database.
My Problem is, i don't understand why the Enum "GlobalType" is not being written into the property.
Everytime i check, the value is 0 instead of "One".
The "Name" property contains the "DateCreated" value.
The "DateCreated" property contains a new DateTime instance.
No other fields, as far as i'm aware of, are doing this.
There is no logic inside of the ViewItemModel, it's just a class with properties.
If i add them after this method manually, everything works.
Maybe someone encountered something similar with subsonic (if it even is subsonic itself, maybe i'm making a mistake)?
I have this method in the Backend:
public IEnumerable<ViewItemModel> LoadView(int registratorId)
{
var itemModel = from item in _itemQuery
join header in _headerQuery on item.HeaderID equals header.ID
where header.RegistratorID == registratorId && !(from hidden in _headerHiddenQuery where hidden.ItemID == item.ID && hidden.Type == GlobalType.One && hidden.RegistratorID == registratorId select hidden.ID).Any()
orderby item.ID descending
select new ViewItemModel()
{
Type = GlobalType.One,
ID = item.ID,
Name = header.Name,
DateCreated = header.DateCreated,
TypeOfTransport = header.TypeOfTransport,
TransportType = item.TransportType,
Count = (from subItems in _subItemQuery where subItems.ItemID == item.ID select subItems.ID).Count(),
// For Status
IsArchived = header.IsArchived,
IsCanceled = header.IsCanceled,
Process = header.Process,
End = header.End,
IsPublished = header.IsPublished,
OpenFrom = header.OpenFrom,
OpenTill = header.OpenTill,
IsNextStarted = header.IsNextStarted
};
return itemModel.ToList();
}
Update:
The GlobalType enum looks like this
public enum GlobalType
{
One = 1,
Two = 2,
Individual = 3
}
If i add them manually, i changed the return statement for this:
var result = itemModel.ToList();
foreach (var item in result)
{
var headerId = _itemQuery.Where(it => it.ID == item.ID).Select(it => it.HeaderID).FirstOrDefault();
var created = _itemQuery.Where(it => it.ID == item.ID).Select(it => it.DateCreated).FirstOrDefault();
var name = _headerQuery.Where(it => it.ID == headerId).Select(it => it.Name).FirstOrDefault();
item.AnnouncementType = GlobalType.One;
item.Name = name;
item.DateCreated = created;
}
return result;
try sample code:
public int enum GlobalType
{
One = 1,
Two = 2,
Individual = 3
}
//enum value Convert to int or other data type using casting
item.AnnouncementType = (int) GlobalType.One;
//Suppose if condition using
if((GlobalType)item.AnnouncementType==GlobalType.One)
{
//your code
}
Thanks to DaveParsons comment, i managed to create a workaround.
In this case, the code will have to iterate twice through the list of found elements, but won't load the entire table into memory.
Since there is a bug (throwing exception) with creating an anonymous object containing multiple classes like so:
select new { item, header, subItems }
I managed to get all the data needed, by manually assigning what i need like so:
public IEnumerable<ViewItemModel> LoadView(int registratorId)
{
var itemModel = from item in _itemQuery
join header in _headerQuery on item.AnnouncementHeaderID equals header.ID
where header.RegistratorID == registratorId && !(from hidden in _headerHiddenQuery where hidden.ItemID == item.ID && hidden.Type == GlobalType.One && hidden.RegistratorID == registratorId select hidden.ID).Any()
orderby item.ID descending
select new {
Type = GlobalType.One,
ID = item.ID,
Name = header.Name,
DateCreated = header.DateCreated,
TypeOfTransport = header.TypeOfTransport,
TransportType = item.TransportType,
Count = (from subItems in _subItemQuery where subItems.ItemID == item.ID select subItems.ID).Count(),
// For Status
IsArchived = header.IsArchived,
IsCanceled = header.IsCanceled,
Process = header.Process,
End = header.End,
IsPublished = header.IsPublished,
OpenFrom = header.OpenFrom,
OpenTill = header.OpenTill,
IsNextStarted = header.IsNextStarted
};
return itemModel
.ToList()
.Select(it => new ViewItemModel() {
Type = it.Type,
ID = it.ID,
Name = it.Name,
DateCreated = it.DateCreated,
TypeOfTransport = it.TypeOfTransport,
TransportType = it.TransportType,
Count = it.Count,
// For Status
IsArchived = it.IsArchived,
IsCanceled = it.IsCanceled,
Process = it.Process,
End = it.End,
IsPublished = it.IsPublished,
OpenFrom = it.OpenFrom,
OpenTill = it.OpenTill,
IsNextStarted = it.IsNextStarted
})
.ToList();
}
Notice: The return value of the query is an anonymous object with every single necessary field declared.
After the database returned all fields with the same name as in the database (model), we then have to force execution with ".ToList()" or something similar (deferred execution?).
Since the data is now in memory, we can assign the values from the anonymous object to the original class that was intended for this purpose.
I am sure there is a more reliable way using reflection, but this is what i have come up with.

How to dynamically GroupBy using Linq

There are several similar sounding posts, but none that do exactly what I want.
Okay, so imagine that I have the following data structure (simplified for this LinqPad example)
public class Row
{
public List<string> Columns { get; set; }
}
public List<Row> Data
=> new List<Row>
{
new Row { Columns = new List<string>{ "A","C","Field3"}},
new Row { Columns = new List<string>{ "A","D","Field3"}},
new Row { Columns = new List<string>{ "A","C","Field3"}},
new Row { Columns = new List<string>{ "B","D","Field3"}},
new Row { Columns = new List<string>{ "B","C","Field3"}},
new Row { Columns = new List<string>{ "B","D","Field3"}},
};
For the property "Data", the user will tell me which column ordinals to GroupBy; they may say "don't group by anything", or they may say "group by Column[1]" or "group by Column[0] and Column[1]".
If I want to group by a single column, I can use:
var groups = Data.GroupBy(d => d.Columns[i]);
And if I want to group by 2 columns, I can use:
var groups = Data.GroupBy(d => new { A = d.Columns[i1], B = d.Columns[i2] });
However, the number of columns is variable (zero -> many); Data could contain hundreds of columns and the user may want to GroupBy dozens of columns.
So the question is, how can I create this GroupBy at runtime (dynamically)?
Thanks
Griff
With that Row data structure what are you asking for is relatively easy.
Start by implementing a custom IEqualityComparer<IEnumerable<string>>:
public class ColumnEqualityComparer : EqualityComparer<IEnumerable<string>>
{
public static readonly ColumnEqualityComparer Instance = new ColumnEqualityComparer();
private ColumnEqualityComparer() { }
public override int GetHashCode(IEnumerable<string> obj)
{
if (obj == null) return 0;
// You can implement better hash function
int hashCode = 0;
foreach (var item in obj)
hashCode ^= item != null ? item.GetHashCode() : 0;
return hashCode;
}
public override bool Equals(IEnumerable<string> x, IEnumerable<string> y)
{
if (x == y) return true;
if (x == null || y == null) return false;
return x.SequenceEqual(y);
}
}
Now you can have a method like this:
public IEnumerable<IGrouping<IEnumerable<string>, Row>> GroupData(IEnumerable<int> columnIndexes = null)
{
if (columnIndexes == null) columnIndexes = Enumerable.Empty<int>();
return Data.GroupBy(r => columnIndexes.Select(c => r.Columns[c]), ColumnEqualityComparer.Instance);
}
Note the grouping Key type is IEnumerable<string> and contains the selected row values specified by the columnIndexes parameter, that's why we needed a custom equality comparer (otherwise they will be compared by reference, which doesn't produce the required behavior).
For instance, to group by columns 0 and 2 you could use something like this:
var result = GroupData(new [] { 0, 2 });
Passing null or empty columnIndexes will effectively produce single group, i.e. no grouping.
you can use a Recursive function for create dynamic lambdaExpression. but you must define columns HardCode in the function.

Intersect between 2 collections in C#

I have:
List<INFRAESTRUCTURA> l1 = listQ1.ToList();
List<INFRAESTRUCTURA> l2 = listQ2.ToList();
And I need to intersect it comparing ids. Something like that:
l1.Intersect(l2, l1[].id_infraestructura == l2[].id_infraestructura)
But I don't know which method I must use and it sintax.
I found this:
var ids = list1.Select(a => a.id).Intersect(list2.Select(b => b.id));
But this return a list of ids and i need a list of elements contained in both lists.
Thank you!
I would use Enumerable.Join:
var intersecting = from i1 in l1
join i2 in l2
on i1.id_infraestructura equals i2.id_infraestructura
select i1;
List<INFRAESTRUCTURA> result = intersecting.ToList();
If you would override Equals + GetHashCode in INFRAESTRUCTURA or provide a custom IEqualityComparer<INFRAESTRUCTURA> you could use Enumerable.Intersect directly:
List<INFRAESTRUCTURA> result = l1.Intersect(l2).ToList();
Here's a possible implementation:
public class InfrastructureComparer : IEqualityComparer<INFRAESTRUCTURA>
{
public bool Equals(INFRAESTRUCTURA x, INFRAESTRUCTURA y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.id_infraestructura == y.id_infraestructura;
}
public int GetHashCode(INFRAESTRUCTURA obj)
{
if (obj == null) return 0;
return obj.id_infraestructura;
}
}
you can use the overloads which take an IEqualityComparer<T> like here:
List<INFRAESTRUCTURA> result = l1.Intersect(l2, new InfrastructureComparer()).ToList();
If you want both objects in the result you could use an anonymous type:
var intersecting = from i1 in l1
join i2 in l2
on i1.id_infraestructura equals i2.id_infraestructura
select new { i1, i2 };
The other answers are correct, but you can use Intersect with your custom comparer. You can create custom comparer by implementing IEqualityComparer<> interface. And for implementing this interface we must implmenet two methods, Equals and GetHashCode.
public class InfraestructuraComparer: IEqualityComparer<INFRAESTRUCTURA>
{
/// <summary>
/// Whether the two INFRAESTRUCTURA are equal.
/// </summary>
public bool Equals(INFRAESTRUCTURA firstObj, INFRAESTRUCTURA secondObj)
{
if (firstObj == null && secondObj == null)
return true;
if (firstObj == null || secondObj == null)
return false;
// Your equality logic goes to here
return firstObj.ID == secondObj.ID;
}
/// <summary>
/// Return the hash code for this instance.
/// </summary>
public int GetHashCode(INFRAESTRUCTURA obj)
{
// Don't compute hash code on null object.
if (obj == null) return 0;
unchecked
{
var hash = 17;
hash = hash * 23 + obj.Id.GetHashCode();
return hash;
}
}
}
And then:
var result = list1.Intersect(list2, new InfraestructuraComparer());
You can also use this comparer in Except method, for finding the difference of two sequences.
var result = list1.Except(list2, new InfraestructuraComparer());
Additionally:
From the first point of view you may misunderstood GetHashCode(). You can read about this method in many question of StackOverflow. You can read the answer to this question.
You can use Linq Join
l1.Join(l2, l => l.id_infraestructura, r => r.id_infraestructura, (l,r) => l.id_infraestructura);

Convert Object to List

I want convert object to list of myclass, which object is return from linq query.
object list = detailManager.GetMutabakatDetailListByMutabakat(oMutabakat, true);
List<CurrentAccount> accountList = ??
GetMutabakatDetailListByMutabakat method like this;
public object GetMutabakatDetailListByMutabakat(Mutabakat mutabakat, bool Gonderen)
{
var detayIdList = this.Context.MutabakatDetay.Where(s => s.MutabakatId == mutabakat.MutabakatId).Select(s => s.MutabakatDetayId).ToList();
var CariEkstreList =
(from ekstre in this.Context.CariHesapEkstre
join detay in this.Context.MutabakatDetay on ekstre.MutabakatDetayId equals detay.MutabakatDetayId
where detayIdList.Contains(ekstre.MutabakatDetayId.Value) && ekstre.GonderenMukellefFirmaId == mutabakat.GonderenMukellefFirmaId
select new
{
MutabakatDetayId = ekstre.MutabakatDetayId,
MutabakatVar = ekstre.MutabakatVar,
AlanFirmaId = ekstre.AlanFirmaId,
GonderenMukellefFirmaId = ekstre.GonderenMukellefFirmaId,
KayitTarihi = ekstre.KayitTarihi,
DonemYil = ekstre.DonemYil,
DonemAy = ekstre.DonemAy,
Degistirildi = ekstre.Degistirildi,
CariHesapEkstreId = ekstre.CariHesapEkstreId,
AktaranKullaniciId = ekstre.AktaranKullaniciId,
AktarimId = ekstre.AktarimId,
AktarimTarihi = ekstre.AktarimTarihi,
BakiyeTur = ekstre.BakiyeTur,
BelgeNo = ekstre.BelgeNo,
BelgeTarihi = ekstre.BelgeTarihi,
BelgeTur = ekstre.BelgeTur,
IslemTarihi = ekstre.IslemTarihi,
ParaBirimi = ekstre.ParaBirimi,
TLTutar = ekstre.BakiyeTur == "B" ? ekstre.TLTutar * -1 : ekstre.TLTutar,
Tutar = ekstre.BakiyeTur == "B" ? ekstre.Tutar * -1 : ekstre.Tutar
}).ToList();
return CariEkstreList;
}
It depends on what list actually is:
A) if detailManager.GetMutabakatDetailListByMutabakat(oMutabakat, true) returns IEnumerable<CurrentAccount> then all you have to do is to add .ToList():
List<CurrentAccount> accountList = detailManager
.GetMutabakatDetailListByMutabakat(oMutabakat, true)
.ToList();
B) if detailManager.GetMutabakatDetailListByMutabakat(oMutabakat, true) returns IEnumerable<SomeObject> and SomeObject can be cast to CurrentAccount then
List<CurrentAccount> accountList = detailManager
.GetMutabakatDetailListByMutabakat(oMutabakat, true)
.OfType<CurrentAccount>()
.ToList();
C) Finally, in the general case you have to implement .Select:
List<CurrentAccount> accountList = detailManager
.GetMutabakatDetailListByMutabakat(oMutabakat, true)
.Select(item => GetAccountFromItem(item)) //TODO: implement Select
.ToList();
Thanks everyone, i solved my problem with using reflaction.
firstly, object casted to IList
List<CariHesapEkstre> senderExtractList = GetExtractList((IList)detayManager.GetMutabakatDetayListByMutabakat(oMutabakat, true));
private List<CariHesapEkstre> GetExtractList ( IList tempList )
{
List<CariHesapEkstre> returnList = new List<CariHesapEkstre>();
foreach ( var item in tempList )
{
CariHesapEkstre extract = new CariHesapEkstre();
foreach ( PropertyInfo prop in item.GetType().GetProperties() )
{
foreach ( PropertyInfo prop2 in extract.GetType().GetProperties() )
{
if ( prop2.Name == prop.Name )
{
prop2.SetValue(extract, prop.GetValue(item));
}
}
}
returnList.Add(extract);
}
return returnList;
}
There are few things I can say,
What does your method GetMutabakatDetailListByMutabakat return? Does it have to be object?
As its name implies - if a methods name is Get...List I would expect it to return a list, not an object. If you can, first change that behaviour then you'll be ok.
If that method is written by someone else(that you cannot change the behaviour) then you should play with casting operations as the others suggest, but you can only do this if the underlying object is really of type List<CurrentAccount>.
And if the underlying object is not even of type List<CurrentAccount> then you should learn what the object structure is(another class, anonymous object, or dynamic) then we can work something out.
After Update
With the update to your question I can see that you are returning a list of anonymous objects. But isn't it actually CurrentAccount?
So if you select it as following:
public List<CariHesapEkstre> GetMutabakatDetailListByMutabakat ( Mutabakat mutabakat, bool Gonderen )
{
var detayIdList = this.Context.MutabakatDetay.Where(s => s.MutabakatId == mutabakat.MutabakatId).Select(s => s.MutabakatDetayId).ToList();
var CariEkstreList =
( from ekstre in this.Context.CariHesapEkstre
join detay in this.Context.MutabakatDetay on ekstre.MutabakatDetayId equals detay.MutabakatDetayId
where detayIdList.Contains(ekstre.MutabakatDetayId.Value) && ekstre.GonderenMukellefFirmaId == mutabakat.GonderenMukellefFirmaId
/// here you only need to use object initializer for CariHesapEkstre like just below
select new CariHesapEkstre
{
MutabakatDetayId = ekstre.MutabakatDetayId,
MutabakatVar = ekstre.MutabakatVar,
...
Tutar = ekstre.BakiyeTur == "B" ? ekstre.Tutar * -1 : ekstre.Tutar
} ).ToList();
return CariEkstreList;
}
Last Update
I see what you are trying to do, you want a method to do the hardwork for you. So you can check this tool called automapper. It does what you are trying to do. But still it's a hard work for your code too.
But if you are only trying to convert an object to a list you can use the code below.
public List<CariHesapEkstre> ConvertToDesiredType ( object list )
{
return ( (IEnumerable<dynamic>)list ).Select(item => new CariHesapEkstre
{
MutabakatDetayId = item.MutabakatDetayId,
MutabakatVar = item.MutabakatVar,
...
}).ToList();
}

How to compare two lists in .NET

List<Employee> emplist = new List<Employee>();
emplist.Add(new Employee { Name = "Emp_1", BasicSalary = 1000, Id = Guid.NewGuid(), HRA = 100, DA = 10, TotalSalary = 1110 });
emplist.Add(new Employee { Name = "Emp_2", BasicSalary = 1000 * 2, Id = Guid.NewGuid(), HRA = 200, DA = 20, TotalSalary = 2220 });
emplist.Add(new Employee { Name = "Emp_3", BasicSalary = 1000 * 3, Id = Guid.NewGuid(), HRA = 300, DA = 30, TotalSalary = 3330 });
var result = empRep.CallSupportFindAll();
// CollectionAssert.AreEqual(emplist, result);
Assert.AreEqual(emplist, result);
var r1 = result[0];
Assert.AreEqual(r1.Name, emplist[0].Name);
Assert.AreEqual(r1.TotalSalary, emplist[0].TotalSalary);
Assert.AreEqual(r1.BasicSalary, emplist[0].BasicSalary);
I want to compare two lists emplist and result. Assert.AreEqual(r1.Name, emplist[0].Name); worked but if we have thousands of records then I need to write thousands of lines.
so please answer-- for one line code for compare two list...
thanks in advance
If I understand correctly, you simply have two instances of List<Employee> and you want to assert that they are equal. I.e. they have the same number of Employee instances, in the same order, with equal properties.
If so, this has nothing to do with FakeItEasy. You simply need a method of performing the assertion. Personally I would do this using Fluent Assertions.
result.Should().BeEquivalentTo(emplist);
You can use HashSet<> to compare the two lists.
First, define an equaliser like this
public class EmployeeComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
if (x == null && y == null)
return true;
if (x == null || y == null)
return false;
//You can implement the equal method as you like. For instance, you may compare by name
if (x.Id == y.Id)
return true;
return false;
}
public int GetHashCode(Employee employee)
{
return employee.Id.GetHashCode();
}
}
Next, create 2 hash sets based on the input and the result of the method
var equaliser = new EmployeeComparer();
HashSet<Employee> inputHashset = new HashSet<Employee>(emplist ,equaliser );
HashSet<Employee> resultHashset = new HashSet<Employee>(result,equaliser);
Finally, assert the equality of the two sets. It means, instead of
Assert.AreEqual(emplist, result);
Do
Assert.IsTrue(inputHashset.SetEquals(resultHashset));
public bool compareTwolist<T>(List<T> lst1,List<T> lst2)
{
bool bresult = false;
if (lst1.GetType() != lst2.GetType())
{
return false;
}
//if any of the list is null, return false
if ((lst1 == null && lst2 != null) || (lst2 == null && lst1 != null))
return false;
//if count don't match between 2 lists, then return false
if(lst1.Count != lst2.Count)
return false;
foreach (T item in lst1)
{
T obj1 = item;
T obj2 = lst2.ElementAt(lst1.IndexOf(item));
Type type = typeof(T);
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
string obj1Value = string.Empty;
string obj2Value = string.Empty;
if (type.GetProperty(property.Name).GetValue(obj1) != null)
obj1Value = type.GetProperty(property.Name).GetValue(obj1).ToString();
if (type.GetProperty(property.Name).GetValue(obj2) != null)
obj2Value = type.GetProperty(property.Name).GetValue(obj2).ToString();
//if any of the property value inside an object in the list didnt match, return false
if (obj1Value.Trim() != obj2Value.Trim())
{
bresult = false;
break;
}
}
}
return bresult;
}
yes, I got a solution by creating user define function and pass two lists which we want to compare..
and just check is var a is true or not
var a = compareTwolist(empwithoutid, resultwithoutid);
Assert.IsTrue(a);
The comparison methods suggested in the other answers require you to implement equals on all your objects. This doesn't scale well from a maintenance perspective. Also in some tests only subset of fields are to be compared. This means multiple compare or equals methods to be implemented. An alternative is stateprinter which dumps state to a string to compare against. It can even write and rewrite your asserts for you. See https://github.com/kbilsted/StatePrinter/blob/master/doc/AutomatingUnitTesting.md for more info on automation and https://github.com/kbilsted/StatePrinter/blob/master/doc/TheProblemsWithTraditionalUnitTesting.md for an in depth discussion on problems with unit testing as you are facing now.

Categories