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();
}
Related
This question already has answers here:
Comparing object properties in c# [closed]
(20 answers)
Closed 4 years ago.
I have a database containing components with about 20 properties. To find out if an update is needed I want to check if all properties for the two objects, except DateCreated and Id, matches.
If all matches no update, if not, update db.
Component comp_InApp = new Component()
{
Id = null,
Description = "Commponent",
Price = 100,
DateCreated = "2019-01-30",
// Twenty more prop
};
Component comp_InDb = new Component()
{
Id = 1,
Description = "Component",
Price = 100,
DateCreated = "2019-01-01",
// Twenty more prop
};
// Check if all properties match, except DateCreated and Id.
if (comp_InApp.Description == comp_InDb.Description &&
comp_InApp.Price == comp_InDb.Price
// Twenty more prop
)
{
// Everything up to date.
}
else
{
// Update db.
}
This works, but it's not a very clean way with 20 properties. Is there a better way of achieiving the same result in a cleaner way?
I am using DeepEqual when I don't want/don't have the time to write myself Equals and GetHashCode methods.
You can install it simply from NuGet with:
Install-Package DeepEqual
and use it like:
if (comp_InApp.IsDeepEqual(comp_InDb))
{
// Everything up to date.
}
else
{
// Update db.
}
But keep in mind that this will only work for your case when you want to explicitly compare objects, but not for the case when you want to remove an object form a List or cases like this, when Equals and GetHashCode are invoked.
One way, create a class that implements IEqualityComparer<Component> to encapsulate this logic and to avoid that you have modify the class Comparer itself(if you don't want this Equals logic all time). Then you can use it for a simple Equals of two instances of Component and even for all LINQ methods that accepts it as additional argument.
class ComponentComparer : IEqualityComparer<Component>
{
public bool Equals(Component x, Component y)
{
if (object.ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return x.Price == y.Price && x.Description == y.Description;
}
public int GetHashCode(Component obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + obj.Price.GetHashCode();
hash = hash * 23 + obj.Description?.GetHashCode() ?? 0;
// ...
return hash;
}
}
}
Your simple use-case:
var comparer = new ComponentComparer();
bool equal = comparer.Equals(comp_InApp, comp_InDb);
It works also if you have two collections and want to know the difference, for example:
IEnumerable<Component> missingInDb = inAppList.Except( inDbList, comparer );
Here is a solution with Reflection:
static bool AreTwoEqual(Component inApp, Component inDb)
{
string[] propertiesToExclude = new string[] { "DateCreated", "Id" };
PropertyInfo[] propertyInfos = typeof(Component).GetProperties()
.Where(x => !propertiesToExclude.Contains(x.Name))
.ToArray();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
bool areSame = inApp.GetType().GetProperty(propertyInfo.Name).GetValue(inApp, null).Equals(inDb.GetType().GetProperty(propertyInfo.Name).GetValue(inDb, null));
if (!areSame)
{
return false;
}
}
return true;
}
You can use a Reflection but it may slow your application. An alternative way of creating that comparator is to generate it with Linq Expressions. Try this code:
public static Expression<Func<T, T, bool>> CreateAreEqualExpression<T>(params string[] toExclude)
{
var type = typeof(T);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => !toExclude.Contains(p.Name))
.ToArray();
var p1 = Expression.Parameter(type, "p1");
var p2 = Expression.Parameter(type, "p2");
Expression body = null;
foreach (var property in props)
{
var pare = Expression.Equal(
Expression.PropertyOrField(p1, property.Name),
Expression.PropertyOrField(p2, property.Name)
);
body = body == null ? pare : Expression.AndAlso(body, pare);
}
if (body == null) // all properties are excluded
body = Expression.Constant(true);
var lambda = Expression.Lambda<Func<T, T, bool>>(body, p1, p2);
return lambda;
}
it will generate an expression that looks like
(Component p1, Component p2) => ((p1.Description == p2.Description) && (p1.Price == p2.Price))
Usage is simple
var comporator = CreateAreEqualExpression<Component>("Id", "DateCreated")
.Compile(); // save compiled comparator somewhere to use it again later
var areEqual = comporator(comp_InApp, comp_InDb);
EDIT: to make it more type safe you can exclude properties using lambdas
public static Expression<Func<T, T, bool>> CreateAreEqualExpression<T>(
params Expression<Func<T, object>>[] toExclude)
{
var exclude = toExclude
.Select(e =>
{
// for properties that is value types (int, DateTime and so on)
var name = ((e.Body as UnaryExpression)?.Operand as MemberExpression)?.Member.Name;
if (name != null)
return name;
// for properties that is reference type
return (e.Body as MemberExpression)?.Member.Name;
})
.Where(n => n != null)
.Distinct()
.ToArray();
var type = typeof(T);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => !exclude.Contains(p.Name))
.ToArray();
/* rest of code is unchanged */
}
Now when using it we have an IntelliSense support:
var comparator = CreateAreEqualExpression<Component>(
c => c.Id,
c => c.DateCreated)
.Compile();
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.
I have a class
public class ReceiptDisplayInfo
{
public string ReceiptItemFor{get;set;}
public string ReceiptItemCategory{get;set;}
public string ReceiptItemReference{get;set;}
public string ReceiptRowCategory{get;set;}
public string ReceiptAmount{get;set;}
}
I have a list
List<List<ReceiptDisplayInfo>> dataSourceToBind ;
My requirement : For every List , if ReceiptRowCategory="Payment" , I have to set the value of ReceiptItemForm,ReceiptItemCategory to blank or null in dataSourceToBind .
I am doing using for loop but this is not the most appreciated approach.
Please assist me in doing using LINQ/Lambda Expression.
dataSourceToBind.ForEach(x =>
{
var innerList = x;
innerList.ForEach(y =>
{
if (y.ReceiptRowCategory == "Payment")
{
y.ReceiptItemFor = null;
y.ReceiptItemCategory = null;
}
});
});
I guess just 2 ForEach calls would suffice, no need to use LINQ here. However, since the transformation logic is quite complicated, I think you should extract it as a method:
private void SomeMethod(ReceiptDisplayInfo info) { // please name this appropriately
if (info.ReceiptRowCategory == "Payment") {
info.ReceiptItemForm = null;
info.ReceiptItemCategory = null;
}
}
And then,
dataSourceToBind.ForEach(x => x.ForEach(SomeMethod));
You can use below code to achieve this-
((from l in list
where l.ReceiptItemCategory == "payment"
select new ReceiptDisplayInfo()
{
ReceiptItemFor = null,
ReceiptItemCategory = null,
ReceiptItemReference = l.ReceiptItemReference,
ReceiptRowCategory = l.ReceiptRowCategory,
ReceiptAmount = l.ReceiptAmount
}).Union(from l in list
where l.ReceiptItemCategory != "payment"
select l)).ToList();
I have a list that could contain eg. the following objects
ObjectFirst {
id = 1;
mode = Constants.Active;
}
ObjectSecond {
id = 2;
mode = Constants.Passive;
}
How can I make a LINQ query that selects the object with "mode = Constants.Active" if that exists and if not it selects the object with the "mode = Constants.Passive"? Only one object should be returned. I would like to solve this with one LINQ query.
I am not sure if that could be done in one query but it could be done in multiple ways, You can try:
var obj = list.Any(r=> r.mode == Constants.Active) ?
list.FirstOrDefault(r=> r.mode == Constants.Active)
list.FirstOrDefault(r=> r.mode == Constants.Passive);
Or:
var obj = list.FirstOrDefault(r=> r.mode == Constants.Active);
if(obj == null)
{
obj = list.FirstOrDefault(r=> r.mode == Constants.Passive);
}
In theory you could order them by the mode, thus giving them a priority, and then return the first. Assuming that Constants.Active is lower than Constants.Passive.
var obj = list.OrderBy(r => r.mode).FirstOrDefault()
Optionally, you could add some extra checking:
var obj = list.Where(r => r.Id == someId).OrderBy(r => r.mode).FirstOrDefault()
I'm thinking of doing the following:
for(LinkedListNode<MyClass> it = myCollection.First; it != null; it = it.Next)
{
if(it.Value.removalCondition == true)
it.Value = null;
}
What I'm wondering is: if simply pointing the it.Value to null actually gets rid of it.
Setting the it.Value to null will not remove the node from the list
Here is one way:
for(LinkedListNode<MyClass> it = myCollection.First; it != null; )
{
LinkedListNode<MyClass> next = it.Next;
if(it.Value.removalCondition == true)
myCollection.Remove(it); // as a side effect it.Next == null
it = next;
}
Surely (with a linked list) you need to change the link.
Eg, if you want to remove B from the LL A-B-C, you need to change A's link to B to C.
I'll admit I'm not familiar with the .NET implementation of linked lists but hopefully that's a start for you.
You are changing the value pointed to by a LinkedListNode; beware that your list will contain a hole (empty node) now.
Instead of A - B - C you are going to have A - null - C, if you "delete" B. Is that what you want to achieve?
If you can convert to using List<> rather than LinkedList<> then you can use the RemoveAll() operation. Pass an anonymous delegate like this;
List<string> list = new List<string>()
{
"Fred","Joe","John"
};
list.RemoveAll((string val) =>
{
return (0 == val.CompareTo("Fred"));
});
All this is using Linq extensions.
If you can't convert to using a list then you can use the ToList<>() method to convert it. But you'll then have to do some clear and insertion operations. Like this;
LinkedList<string> str = new LinkedList<string>();
str.AddLast("Fred");
str.AddLast("Joe");
str.AddLast("John");
List<string> ls = str.ToList();
ls.RemoveAll((string val) => val.CompareTo("Fred") == 0);
str.Clear();
ls.ForEach((string val) => str.AddLast(val));
If all this still isn't palatable then try doing a copy of the LinkedList like this;
LinkedList<string> str = new LinkedList<string>();
str.AddLast("Fred");
str.AddLast("Joe");
str.AddLast("John");
LinkedList<string> strCopy = new LinkedList<string>(str);
str.Clear();
foreach (var val in strCopy)
{
if (0 != val.CompareTo("Fred"))
{
str.AddLast(val);
}
}
I hope that helps.
I assume something like this is required
for ( LinkedListNode<MyClass> it = myCollection.First; it != null; it = it.Next ) {
if ( it.Value.removalCondition == true ) {
if ( it.Previous != null && it.Next != null ) {
it.Next.Previous = it.Previous;
it.Previous.Next = it.Next;
} else if ( it.Previous != null )
it.Previous.Next = it.Next;
} else if ( it.Next != null )
it.Next.Previous = it.Previous;
it.Value = null;
}
}
As far as I understood You want to iterate in linkedlist with for cycle which olso contains null -s , so you can use folowing :
for (LinkedListNode<string> node = a.First; node != a.Last.Next; node = node.Next)
{
// do something here
}