Replace all values in IQueryable with string based on results using LINQ - c#

I have an IQueryable I selected from a database that contains a field called "NewValue". This field will either contain a 0, 1, or 2. I want to replace the value with a string based of which number it is.
i.e 0 = "Active". I know IQueryables aren't used to change values mostly just for querying but I need to use it in the next line to add to the ViewModel
var AssessmentList = assessment
.Select(p => new LogManagementViewModel
{
newValue = p.NewValue,
});
How can I change all the values in assement.NewValue to a string?

var dictionary = new Dictionary<int, string>
{
{ 0, "Active" },
{ 1, "Inactive" },
// etc
};
var AssessmentList = assessment
.Select(p => new LogManagementViewModel
{
newValue = dictionary[p.NewValue],
});
This would work for mapping between other types as well.

var values = new [] {"StrValue1", "StrValue2", "StrValue"};
var AssessmentList = assessment
.AsEnumerable()
.Select(p => new LogManagementViewModel
{
newValue = values[p.NewValue],
});

Easiest and cleanest would be with a mapping method:
string MapToString(int value)
{
//..
}
var AssessmentList = assessment
.Select(p => new LogManagementViewModel
{
NewValue = MapToString(p.NewValue),
});

One way:
Add a new computed property onto your class (assuming you have a partial class outside of any generated code). Then that computed class can do the translation however it needs to. Your view model can reference this computed value.

I would make a constructor overload in your LogManagementViewModel that does that work for you, something like this:
public LogManagementViewModel(int NewValue)
{
switch(NewValue)
{
case 0:
this.NewValue = "Active";
break;
// etc...
}
}
IMO, this places the logic in it's proper place, let the your view model translate it as it should be, it's not the responsibility of your LINQ/Database queries.

Related

Loop through class properties and get distinct values

How can I do this without going through each class property separately? I have a class with 54 properties that I want to go through and retrieve values from CosmosDB and then use those Distinct values from each property to create a dropdownfo in the view.
I can do them all separately - this code works fine. But to do that for all the properties... there has to be an easier way.
I have to do this with bankCountryCode, Currency, etc. All properties of a class FieldMasterInfo.
IEnumerable<string> fieldId = allItems.Select(m => m.FieldId).Distinct();
var fieldSL = new List<SelectListItem>();
foreach (var element in fieldId)
{
// adding null check here until cosmos db with null tenant id's for tax are removed.
if (element != null)
{
fieldSL.Add(new SelectListItem
{
Value = element.ToString(),
Text = element.ToString()
});
}
}
fieldSL = fieldSL.OrderBy(x => x.Text).ToList();
ViewBag.fieldIdList = fieldSL;
Update
This worked perfectly. It loops through a class and get's the distinct values from each property and puts it into a Dictionary>
FieldMasterInfo fmi = new FieldMasterInfo();
PropertyInfo[] properties = fmi.GetType().GetProperties();
Dictionary<string, IEnumerable<object>> sl = new Dictionary<string, IEnumerable<object>>();
foreach (PropertyInfo property in properties)
{
sl[property.Name] = allItems.Select(m => m.GetType().GetProperty(property.Name).GetValue(m, null)).Distinct();
}
Pass in your fields as text in an array, then use reflection to dynamically read the property.
var fieldNames = new string[] {"bankCountryCode", "Currency" };
foreach(var fieldName in fieldNames)
{
IEnumerable<string> fieldId = allItems.Select(m =>
m.GetType().GetProperty(fieldName).GetValue(m, null)).Distinct();
var fieldSL = new List<SelectListItem>();
foreach (var element in fieldId)
{
// adding null check here until cosmos db with null tenant id's for tax are removed.
if (element != null)
{
fieldSL.Add(new SelectListItem
{
Value = element.ToString(),
Text = element.ToString()
});
}
}
fieldSL = fieldSL.OrderBy(x => x.Text).ToList();
ViewBag.fieldIdList = fieldSL;
}
I confess I did not understand your question clearly. But is this what you need? (I could not test, I wrote right here.)
IEnumerable<string> fieldId = allItems.Select(m => m.FieldId).Distinct();
var fieldSL = fieldId.Where(f => !string.IsNullOrEmpty(f)).Select(x => new SelectListItem { Text = f, Value = f })).OrderBy(i => i.Text).ToList();
ViewBag.fieldIdList = fieldSL;
Either way, better clarify the situation so others can help you. If you need smaller code or another logic or business solution ...

Linq queries in asp.net

I have this function below which is used to get those roles which are not already assigned. I have two list now.
One which has all the roles and the other one which has those roles which are already assigned to that user.
How do I return only those which are present in allRoles but not in alreadyHaveRoles?
public dynamic GiveRolesWhichAreNotAssignedToThisUser(String token, String selectedUser, String selectedOrganization)
{
User u = InstaFood.Core.User.Get(selectedUser);
var allRoles = RolesType.GetByOrganizationType(selectedOrganization).Select(i => new
{
ID = i.Id,
Name = i.Name
});
var alreadyHaveRoles = u.GetUserRoles().Select(i => new
{
ID = i.roleTypeId,
Name = ""
});
return ?? // what should be done here?
}
Can I compare them now given that both have same attributes now?
You can use Except to return the difference of two sequences, eg:
var difference=allRoles.Except(alreadyHaveRoles);
This assumes the two sequences contain items of the same type. The objects are checked for equality using their Equals implementation.
If you want to use your own equality comparison, you need to either have your objects implement IEquatable or create a custom EqualityComparer and use the Except overload that accepts a custom EqualityComparer.
In your case, you return two anonymous types that don't even have the same fields. A human would have to guess how to compare the two types, a computer will simply refuse to compile the code. If you consider two items equal if the IDs are equal, simply return the IDs, eg:
var allRoleIds = RolesType.GetByOrganizationType(selectedOrganization)
.Select(i => i.Id);
var assignedRoleIds = u.GetUserRoles().Select(i => i.roleTypeId);
var unassignedRoleIds=allRoleIds.Except(assignedRoleIds);
Retrieving the unassigned roles is trivial after that, just use:
var unassignedRoles=RolesType.GetByOrganizationType(selectedOrganization)
.Where(role=>unassingedRoleIds.Contains(role.Id);
public dynamic GiveRolesWhichAreNotAssignedToThisUser(String token, String selectedUser, String selectedOrganization)
{
User u = InstaFood.Core.User.Get(selectedUser);
var allRoles = RolesType.GetByOrganizationType(selectedOrganization).Select(i => new
{
ID = i.Id,
Name = i.Name
});
var alreadyHaveRoles = u.GetUserRoles().Select(i => new
{
ID = i.roleTypeId,
Name = ""
});
return allRoles.Where(i=>!alreadyHaveRoles.Contains(i));
}
Not tried but it should work

Condense similiar methods into one mega cool method

I'm trying to remove duplicated code and run into an issue here:
I've got five very similar entities (different asset types, e.g. Bonds, Stocks). The methods I'm trying to condense return some statistics about these assets. The statistics are obtained with the help of Linq, the queries are almost identical.
Before, I had five separate methods in my controller (e.g. BondStatistics, StockStatistics). One of these would look like this (db is my database context which has each asset type defined):
public JsonResult BondStatistics()
{
var items = db.Bonds.ToList();
var result = new[]
{
new
{
key = "Bonds",
values = items.Select(i =>
new {
x = i.priceChangeOneDayInEuro,
y = i.priceChangeTotalInEuro,
size = i.TotalValueInEuro,
toolTip = i.Description
}
)
},
};
return Json(result, JsonRequestBehavior.AllowGet);
}
I googled that one way to rewrite these into just one method could be using reflection. However, I thought I could use a dirty shortcut, something like this:
public JsonResult Scatter(string asset)
{
if (asset == "Stocks") { var items = db.Stocks.ToList(); };
if (asset == "Bonds") { var items = db.Bonds.ToList(); };
if (asset == "Futures") { var items = db.Futures.ToList(); };
if (asset == "Options") { var items = db.Options.ToList(); };
if (asset == "Funds") { var items = db.Funds.ToList(); }
var result = new[]
{
new
{
key = asset,
values = items.Select(i =>
new {
x = i.priceChangeOneDayInEuro,
y = i.priceChangeTotalInEuro,
size = i.TotalValueInEuro,
toolTip = i.Description
}
)
},
};
return Json(result, JsonRequestBehavior.AllowGet);
}
This leads to the problem that the type of "items" is not known in the Linq query at design time.
What would be a good way to overcome this problem? Use some totally other pattern, do use reflection or is there an easy fix?
EDIT
As suggested, I created an Interface and let the BaseAsset-class implement it. Then, changing the condensed method to
List<IScatter> items = new List<IScatter>();
if (asset == "Stocks") { items = db.Stocks.ToList<IScatter>(); };
if (asset == "Bonds") { items = db.Bonds.ToList<IScatter>(); };
if (asset == "Futures") { items = db.Futures.ToList<IScatter>(); };
if (asset == "Options") { items = db.Options.ToList<IScatter>(); };
if (asset == "Funds") { items = db.Funds.ToList<IScatter>(); }
works, at design time at last. Thank you very much!
You are putting everything into var, but what exactly is the type of the items you are processing?
If it would be List<Stock> for db.Stocks.ToList(), List<Bond> for db.Bonds.ToList() you can simply define an interface (e.g. IHasPriceInformation) which has the fields you are using in the LINQ query. Then, Let Stock, Bond and others implement this interface (or provide an abstract base implementation of them) and simply run your LINQ Query on a List<IHasPriceInformation>.

Linq group by using reflection

I have data table "Car" which have 3 cols (owner, carType, colour). My question is how can i make the grouping portion more dynamic by using reflection. my idea is add the grouping col in to array, then use the reflection on the query grouping part. however i was struck at the reflection..
var gcols = new string[] { "owner", "carType" };
var reseult = dt.AsEnumerable()
.GroupBy(x => new
{
carType = x.Field<string>("carType"),
colour = x.Field<string>("colour")
})
.Select(x => new
{
CarType = x.Key.carType,
Colour = x.Key.colour,
count = x.Count()
})
.OrderBy(x => x.CarType).ToList();
If you added this extension method to object:
public static T Field<T>(this object source, string FieldName)
{
var type = source.GetType();
var field = type.GetField(FieldName);
return (T)field.GetValue(source);
}
You'd be able to use the syntax you've posted in your code.
I've not added any safety checking here so it'll need cleaning up, but it'll get you going. Ideally you'd want to check that the type of field is the same as T and a few other checks.

Getting the value of an item from a SelectListItem List?

I have the following class:
public static IEnumerable<SelectListItem> GetDatastore()
{
return new[]
{
new SelectListItem { Value = "DEV", Text = "Development" },
new SelectListItem { Value = "DC1", Text = "Production" },
};
}
What I need is to execute a function to return the Datastore name. Something like
var abc = getDatastoreName("DEV").
Do I need to do this with LINQ or is there some easy way? How could I code this function?
public static string getDatastoreName(string name)
{
var result = GetDatastore().SingleOrDefault(s => s.Value == name);
if (result != null)
{
return result.Text;
}
throw /* some exception */
}
The Value property of SelectListItem is usually unique and hence I have SingleOrDefault(). If that is not the case then you can switch to using FirstOrDefault().
A simple LINQ query can find the value you want:
var val = dataStore.Where(d => d.Value == "DEV").FirstOrDefault();
//`val` will be the item, or null if the item doesn't exist in the list
But this is only good for small lists of items -- it's worst-case Order N.
If you wanted a better search, you could store your data as a dictionary with the keys being used as item values, for example, and databind against that rather than against a list of SelectListItems. That would allow you to look up the values constant time.
For most cases, simple LINQ will be fine. If you have a big list, or you're querying that list frequently... consider an alternative.
Maybe you are searching something like this
i have "Details" page that works perfectly:
#Html.DisplayFor(model => model.Code1dItems.SingleOrDefault(m => m.Value == model.Code1Id.ToString()).Text, new { #class = "Width100P" })
In my model :
Code1Id is int value and it comes from database Code1dItems is IEnumerable
value like 'GetDatastore' and returns ID->string, ID value matches with Code1d and Text->string
depending on your question you should use :
string abc = GetDatastore.SingleOrDefault(m => m.Value == "DEV").Text
if you get value from database you should use my code example.

Categories