Is their anyway of changing the below to included all fields names only and values one thing i noticted that when testing this it also brought other information about the entitiy back im only wanting the fields that have been entered or changed by the user??
public static string ObjectToNotes(object obj)
{
if (obj == null)
{
throw new ArgumentNullException("obj", "Value can not be null or Nothing!");
}
StringBuilder sb = new StringBuilder();
Type t = obj.GetType();
PropertyInfo[] pi = t.GetProperties();
for (int index = 0; index < pi.Length; index++)
{
sb.Append(pi[index].GetValue(obj, null));
if (index < pi.Length - 1)
{
sb.Append(Environment.NewLine);
}
}
return sb.ToString();
}
Right now this will save out the values for the entity only passed
As you can see from the image above the code is getting the values ok and fields but just not any drop downs related text
Help
Need more help with this how do i get the value of reference lookup values using the above method its only priting out the entity reference not the actual text value can this be done
Assuming by entered by the user you mean not having a string representation that is null or empty then try the following:
var properties = t.GetProperties();
var values = properties.Select(p => p.GetValue(obj, null)).Where(v => v != null && !string.IsNullOrEmpty(p.ToString());
var result = string.Join(Environment.NewLine, values);
In order to determine whcih fields have changed, you will need to pass two objects. One representing the entity in its pre-changed state and the other in its post-changed state and compare the properties:
var properties = t.GetProperties();
var before = properties.Select(p => new { property = p, value = p.GetValue(prechange, null) }).Where(v => v.value != null && !string.IsNullOrEmpty(p.value.ToString()).ToDictionary(p => p.property.Name, p => p.value);
var after = properties.Select(p => new { property = p, value = p.GetValue(postchange, null) }).Where(v => v.value != null && !string.IsNullOrEmpty(p.value.ToString()).ToDictionary(p => p.property.Name, p => p.value);
// You can then compare the keys / values of before and after dictionaries here
Related
I have the following Method (I exemplify what I need in the comments of the method):
public static Dictionary<int, int> Foo(bool os, bool rad, bool aci, bool outr, string distrito = null)
{
if (os == false && rad == false && aci == false && outr == false)
{
return new Dictionary<int, int>();
}
var parameters = MethodBase.GetCurrentMethod().GetParameters();
foreach (ParameterInfo parameter in parameters)
{
// I would love if parameter.Value existed, because:
// if (parameter.Value==true) {
// x++
// if (x == 1) string s = "true" + parameter.Name;
// if (x > 1) s += "Additional true" + parameter.Name;
// }
// s += "End";
}
return null;
}
I have to know if one or more values of the bool parameters are true. Since they are four, imagine the combination of if I would have to do to check if only one is true, or if more than one, which are true.
So, how can I cycle the current value of the incoming Method parameters without using the parameter variable itself?
If you only want to know how many are true, you can turn them into integers and add their values:
var values = new[] {os, rad, aci, outr};
var sum = values.Select(v => Convert.ToInt32(v)).Sum();
If you need the name of the parameters, then you can create an anonymous object and read its properties:
public static Dictionary<int, int> Foo(bool os, bool rad, bool aci, bool outr, string distrito = null)
{
var obj = new { os, rad, aci, outr};
foreach (PropertyInfo pInfo in obj.GetType().GetProperties())
{
var value = (bool)pInfo.GetValue(obj);
if (value)
{
//Do whatever you want here.
Console.WriteLine("{0}: {1}", pInfo.Name, value);
}
}
}
You can try some LINQ extensions, I think composition of Where and Select may be a solution, with a string.Join method on top:
// get all parameters
var parameters = MethodBase.GetCurrentMethod().GetParameters();
// for each true parameter we add this prefix
var truePrefix = "true";
// we put this string between true parameters, if more than one are present
var separator = "Additional";
// Join IEnumerable of strings with a given separator
var total = string.Join(separator, parameters
// filter parameters to check only boolean ones, and only true ones
.Where(p => p.ParameterType == typeof(bool) && (bool)p.Value)
// select a name with prefix
.Select(p => truePrefix + p.Name)))
I have a collection of items that may have one or more properties.
I want to use a Linq statement (query syntax) to filter and group that list in a single pass such that it checks for a mandatory property first, and then looks for an optional property.
I can't figure out how to do this without first filtering the list and then going over it again to look for the optional property.
Here's how I could do it in a foreach statement. (Not efficient, just illustrating what I need.)
var usefulBoxes = new Dictionary<Box, int>;
foreach (box in cart)
{
bool boxNeeded = false;
int someCounter = 0;
foreach (prop in box.Properties)
{
if (prop == neededProp)
boxNeeded = true;
else if (boxNeeded && prop == optionalProp)
someCounter += 1;
}
if (boxNeeded)
usefulBoxes.Add(box, someCounter)
}
var usefulBoxes= box.where(b=>b.boxProperties.prop==neededProp).ToList();
this your demo linq:
var usefulBoxes = new Dictionary<List<int>, int>();
foreach (var boxNeeded in from box in cart let boxNeeded = false let someCounter = 0 from prop in box.Properties.Where(prop => prop == neededProp) select boxNeeded)
{
if (prop == neededProp)
boxNeeded = true;
else if (boxNeeded && prop == optionalProp)
someCounter += 1;
if (boxNeeded)
usefulBoxes.Add(box, someCounter);
}
Alright, so I need to get the key value paired differences of two data rows. In short, I'm sending an email to let a user know they've made specific changes to their profile. I already know the rows are different because I'm using the SequenceEqual to determine that.
At the moment I've written and debugged the following code:
if (currentRow.ItemArray.SequenceEqual(updatedRow)) { return; }
var updates = currentRow.ItemArray
.Where((o, i) =>
{
if (o == null && updatedRow[i] == null) { return false; }
else if (o == null && updatedRow[i] != null) { return true; }
else if (o.Equals(updatedRow[i])) { return false; }
return true;
})
.Select((o, i) =>
{
return new AppServices.NotificationData
{
Key = updatedRow.Table.Columns[i].ColumnName,
Value = Convert.ToString(updatedRow[i])
};
}).ToList();
But there are two problems with this code:
It seems really inefficient to me because it's going through each value in the ItemArray and then building a key value pair if the values differ.
It doesn't actually work because the i sent into the Select isn't correct (e.g. if the second column changed, 1, the index sent into the Select is actually 0. Honestly, that makes sense, but I'm not sure exactly how to get what I want here.
CONSTRAINT: I'd like to use LINQ here.
NOTE: I'm only comparing two rows (i.e. it's not going to be going through a list of rows).
What is the appropriate LINQ statement for what I'm trying to do here?
UPDATE: It really feels like I just need to use:
currentRow.ItemArray.Intersect(updatedRow.ItemArray)
but the problem with that is I don't have any idea what field that is so I can't build a key value pair. In other words, I get back only the differences, but I've no clue what the index is so I can't go get a column name based off of those values.
Honestly you're not going to lose much code clarity by using a for loop.
public IEnumerable<AppServices.NotificationData> GetUpdates(DataRow currentRow, DataRow updatedRow)
{
if (currentRow.ItemArray.SequenceEqual(updatedRow)) yield break;
var length = currentRow.ItemArray.Length;
for(var i = 0; i < length; i++)
{
var currentCol = currentRow[i];
var updatedCol = updatedRow[i];
if (currentCol == null && updatedCol == null) continue;
else if (currentCol == null && updatedCol != null) continue;
else if (currentCol.Equals(updatedCol)) continue;
yield return new AppServices.NotificationData
{
Key = updatedRow.Table.Columns[i].ColumnName,
Value = Convert.ToString(updatedCol)
};
}
}
var updates = currentRow.ItemArray
.Select((o, i) => new { Row = o, Index = i })
.Where(r => (r.Row == null && updatedRow[r.Index] != null)
|| (r.Row != null && updatedRow[r.Index] != null
&& !r.Row.Equals(updatedRow[r.Index])))
.Select(r => new
{
Key = updatedRow.Table.Columns[r.Index].ColumnName,
Value = Convert.ToString(updatedRow[r.Index])
}).ToList();
In general, I consider using array index values in LINQ to be a "code smell", and this is a good example of why: the Where clause, in generating a new sequence of values, destroys the illusion that the Select clause is working on the same collection as before.
A quick hack to get around this right now (though I don't think it is quite yet the right solution), would be to swap your Where and Select clauses, essentially:
if (currentRow.ItemArray.SequenceEqual(updatedRow)) { return; }
var updates = currentRow.ItemArray
.Select((o, i) =>
{
if (o == null && updatedRow[i] == null || o.Equals(updatedRow[i])) { return null; }
else return new AppServices.NotificationData
{
Key = updatedRow.Table.Columns[i].ColumnName,
Value = Convert.ToString(updatedRow[i])
};
}).Where(o => o != null).ToList();
I have a method that gets a list of objects and then returns all their properties values based on the attributes and types of the property.
I'm having difficulties with selecting the value because the Select depends on conditions.
What I did so far allows me to get the value in the ugliest way I have ever seen:
public IEnumerable<string> GetValues(List<ProperyInfo> objects)
{
var allValues = new List<string>();
foreach (var obj in objects)
{
// Get the PropertyInfo for the obj
var properties = GetPropertiesWithTheAttributes(obj);
var values = properties.Select(x => new
{
Value = x.GetValue(obj, null) == null
? string.empty
:
x.PropertyType.BaseType == typeof(Enum)
? Convert.ToInt32(x.GetValue(obj, null)).ToString()
: (x.GetValue(obj, null)).ToString(),
((ReportAttribute)
Attribute.GetCustomAttribute(x, typeof(ReportAttribute), false)).Order
})
.OrderBy(x => x.Order)
.Select(x => x.Value.ToString())
.ToList();
allValues.AddRange(values);
}
return allValues;
}
And in the code I published here I even removed the check for the DisplayDate property in the ReportAttribute, which verifies if the datetime property of the attribute would be displayed as date or datetime...
serenity now!
I would simply extract this into 2 methods, and get rid of the ternary operator:
// not sure how to name 'obj' and 'x' without more context
private static object GetValue(PropertyInfo obj, PropertyInfo x)
{
if (x.GetValue(obj, null) == null) return string.Empty;
if (x.PropertyType.BaseType == typeof (Enum))
return Convert.ToInt32(x.GetValue(obj, null));
return x.GetValue(obj, null);
}
private static int GetOrder(PropertyInfo x)
{
return ((ReportAttribute) Attribute.GetCustomAttribute(x, typeof(ReportAttribute), false)).Order;
}
So you can write:
public IEnumerable<string> GetValues(List<PropertyInfo> objects)
{
var allValues = new List<string>();
foreach (var obj in objects)
{
// Get the PropertyInfo for the obj
var properties = GetPropertiesWithTheAttributes(obj);
var values = properties.Select(x => new
{
Value = GetValue(obj, x),
Order = GetOrder(x)
})
.OrderBy(x => x.Order)
.Select(x => x.Value.ToString())
.ToList();
allValues.AddRange(values);
}
return allValues;
}
If you really want to inline this, you can change the lambda expression in your Select to a statement:
.Select(x =>
{
object value;
if (x.GetValue(obj, null) == null) value = string.Empty;
else if (x.PropertyType.BaseType == typeof (Enum))
value = Convert.ToInt32(x.GetValue(obj, null));
else value = x.GetValue(obj, null);
return new
{
Value = value,
((ReportAttribute)
Attribute.GetCustomAttribute(x, typeof (ReportAttribute), false)).
Order
};
})
Here I have a simple example to find an item in a list of strings. Normally I use a for loop or anonymous delegate to do it like this:
int GetItemIndex(string search)
{
int found = -1;
if ( _list != null )
{
foreach (string item in _list) // _list is an instance of List<string>
{
found++;
if ( string.Equals(search, item) )
{
break;
}
}
/* Use an anonymous delegate
string foundItem = _list.Find( delegate(string item) {
found++;
return string.Equals(search, item);
});
*/
}
return found;
}
LINQ is new for me. Can I use LINQ to find an item in the list? If it is possible, how?
There are a few ways (note that this is not a complete list).
Single will return a single result, but will throw an exception if it finds none or more than one (which may or may not be what you want):
string search = "lookforme";
List<string> myList = new List<string>();
string result = myList.Single(s => s == search);
Note that SingleOrDefault() will behave the same, except it will return null for reference types, or the default value for value types, instead of throwing an exception.
Where will return all items which match your criteria, so you may get an IEnumerable<string> with one element:
IEnumerable<string> results = myList.Where(s => s == search);
First will return the first item which matches your criteria:
string result = myList.First(s => s == search);
Note that FirstOrDefault() will behave the same, except it will return null for reference types, or the default value for value types, instead of throwing an exception.
If you want the index of the element, this will do it:
int index = list.Select((item, i) => new { Item = item, Index = i })
.First(x => x.Item == search).Index;
// or
var tagged = list.Select((item, i) => new { Item = item, Index = i });
int index = (from pair in tagged
where pair.Item == search
select pair.Index).First();
You can't get rid of the lambda in the first pass.
Note that this will throw if the item doesn't exist. This solves the problem by resorting to nullable ints:
var tagged = list.Select((item, i) => new { Item = item, Index = (int?)i });
int? index = (from pair in tagged
where pair.Item == search
select pair.Index).FirstOrDefault();
If you want the item:
// Throws if not found
var item = list.First(item => item == search);
// or
var item = (from item in list
where item == search
select item).First();
// Null if not found
var item = list.FirstOrDefault(item => item == search);
// or
var item = (from item in list
where item == search
select item).FirstOrDefault();
If you want to count the number of items that match:
int count = list.Count(item => item == search);
// or
int count = (from item in list
where item == search
select item).Count();
If you want all the items that match:
var items = list.Where(item => item == search);
// or
var items = from item in list
where item == search
select item;
And don't forget to check the list for null in any of these cases.
Or use (list ?? Enumerable.Empty<string>()) instead of list.
Do you want the item in the list or the actual item itself (would assume the item itself).
Here are a bunch of options for you:
string result = _list.First(s => s == search);
string result = (from s in _list
where s == search
select s).Single();
string result = _list.Find(search);
int result = _list.IndexOf(search);
If it really is a List<string> you don't need LINQ, just use:
int GetItemIndex(string search)
{
return _list == null ? -1 : _list.IndexOf(search);
}
If you are looking for the item itself, try:
string GetItem(string search)
{
return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search));
}
This method is easier and safer
var lOrders = new List<string>();
bool insertOrderNew = lOrders.Find(r => r == "1234") == null ? true : false
How about IndexOf?
Searches for the specified object and returns the index of the first occurrence within the list
For example
> var boys = new List<string>{"Harry", "Ron", "Neville"};
> boys.IndexOf("Neville")
2
> boys[2] == "Neville"
True
Note that it returns -1 if the value doesn't occur in the list
> boys.IndexOf("Hermione")
-1
This will help you in getting the first or default value in your LINQ List search
var results = _List.Where(item => item == search).FirstOrDefault();
This search will find the first or default value, which it will return.
I used to use a Dictionary which is some sort of an indexed list which will give me exactly what I want when I want it.
Dictionary<string, int> margins = new Dictionary<string, int>();
margins.Add("left", 10);
margins.Add("right", 10);
margins.Add("top", 20);
margins.Add("bottom", 30);
Whenever I wish to access my margins values, for instance, I address my dictionary:
int xStartPos = margins["left"];
int xLimitPos = margins["right"];
int yStartPos = margins["top"];
int yLimitPos = margins["bottom"];
So, depending on what you're doing, a dictionary can be useful.
If we need to find an element from the list, then we can use the Find and FindAll extensions method, but there is a slight difference between them. Here is an example.
List<int> items = new List<int>() { 10, 9, 8, 4, 8, 7, 8 };
// It will return only one 8 as Find returns only the first occurrence of matched elements.
var result = items.Find(ls => ls == 8);
// this will returns three {8,8,8} as FindAll returns all the matched elements.
var result1 = items.FindAll(ls => ls == 8);
Here is one way to rewrite your method to use LINQ:
public static int GetItemIndex(string search)
{
List<string> _list = new List<string>() { "one", "two", "three" };
var result = _list.Select((Value, Index) => new { Value, Index })
.SingleOrDefault(l => l.Value == search);
return result == null ? -1 : result.Index;
}
Thus, calling it with
GetItemIndex("two") will return 1,
and
GetItemIndex("notthere") will return -1.
Reference: linqsamples.com
Try this code:
return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID });
You can use FirstOfDefault with the Where LINQ extension to get a MessageAction class from the IEnumerable. Reme
var action = Message.Actions.Where(e => e.targetByName == className).FirstOrDefault<MessageAction>();
where
List<MessageAction> Actions { get; set; }
One more way to check the existence of an element in a List<string>:
var result = myList.Exists(users => users.Equals("Vijai"))
You want to search an object in object list.
This will help you in getting the first or default value in your Linq List search.
var item = list.FirstOrDefault(items => items.Reference == ent.BackToBackExternalReferenceId);
or
var item = (from items in list
where items.Reference == ent.BackToBackExternalReferenceId
select items).FirstOrDefault();