Assign Value in List using lambda expression - c#

I have following classes:
public class ProviderQualificationTimeViewModel
{
public string SessionId { get; set; }
public List<ProviderQualificationDetail> ProviderQualificationDetails { get; set; }
}
public class ProviderQualificationDetail
{
public string ProviderName { get; set; }
public string ProviderQualificationTime { get; set; }
public string TotalServiceableOffers { get; set; }
}
Basically, I want to create a new object if condition is true else I want to update ProviderQualificationDetail.ProviderQualificationTime where ProviderQualificationDetail.ProviderName == providerName
Is it possible using lambda expression?
List<ProviderQualificationDetail> providerQualificationDetail = new List<ProviderQualificationDetail>();
foreach (ProviderModel providers in allProviders)
{
if(!providerQualificationDetail.Any(p=>p.ProviderName.Contains(providerName)))
{
ProviderQualificationDetail ProviderQualificationDetail = new ProviderQualificationDetail();
ProviderQualificationDetail.ProviderName = providerName;
ProviderQualificationDetail.ProviderQualificationTime = Math.Round(processingTime).ToString();
ProviderQualificationDetail.TotalServiceableOffers = "Not serviceable";
providerQualificationDetail.Add(ProviderQualificationDetail);
}
else
{
//Lambda expression here
}
}

like this in else part:
foreach (var item in providerQualificationDetail.Where(x => x.ProviderName== providerName))
{
item.ProviderQualificationTime = Math.Round(processingTime).ToString();
}
Or
providerQualificationDetail.Where(x => x.ProviderName == ProviderName).Select(c =>
{
c.ProviderQualificationTime = "new time ";
return providerQualificationDetail;
}).ToList();
Or
providerQualificationDetail.ForEach(x =>
{
if(x.ProviderName == ProviderName)
x.ProviderQualificationTime = "new time";
});

Try this....
List<ProviderQualificationDetail> providerQualificationDetail = new List<ProviderQualificationDetail>();
foreach (ProviderModel providers in allProviders)
{
if(!providerQualificationDetail.Any(p=>p.ProviderName.Contains(providerName)))
{
ProviderQualificationDetail ProviderQualificationDetail = new ProviderQualificationDetail();
ProviderQualificationDetail.ProviderName = providerName;
ProviderQualificationDetail.ProviderQualificationTime = Math.Round(processingTime).ToString();
ProviderQualificationDetail.TotalServiceableOffers = "Not serviceable";
providerQualificationDetail.Add(ProviderQualificationDetail);
}
else
{
var qualificationDetail = providerQualificationDetail.SingleOrDefault(p => p.ProviderName.Equals(providerName));
//Assing your values here
//example;
qualificationDetail.ProviderName = NewProviderName.ToString();
providerQualificationDetail.SaveChanges();
}
}

Related

c# how to access all instances of a class outside of the function?

I am new to C# and OOP, in general, I've kinda hit a wall I am reading in this CSV using the CSV Helper package, but there are some unwanted rows, etc so I have cleaned it up by iterating over "records" and creating a new class LineItems.
But Now I appear to be a bit stuck. I know void doesn't return anything and is a bit of a placeholder. But How can I access all the instances of LineItems outside of this function?
public void getMapper()
{
using (var StreamReader = new StreamReader(#"D:\Data\Projects\dictUnitMapper.csv"))
{
using (var CsvReader = new CsvReader(StreamReader, CultureInfo.InvariantCulture))
{
var records = CsvReader.GetRecords<varMapper>().ToList();
foreach (var item in records)
{
if (item.name != "#N/A" && item.priority != 0)
{
LineItems lineItem = new LineItems();
lineItem.variableName = item.Items;
lineItem.variableUnit = item.Unit;
lineItem.variableGrowthCheck = item.growth;
lineItem.variableAVGCheck = item.avg;
lineItem.variableSVCheck = item.svData;
lineItem.longName = item.name;
lineItem.priority = item.priority;
}
}
}
}
}
public class LineItems
{
public string variableName;
public string variableUnit;
public bool variableGrowthCheck;
public bool variableAVGCheck;
public bool variableSVCheck;
public string longName;
public int priority;
}
public class varMapper
{
public string Items { get; set; }
public string Unit { get; set; }
public bool growth { get; set; }
public bool avg { get; set; }
public bool svData { get; set; }
public string name { get; set; }
public int priority { get; set; }
}
You should write your method to return a list.
public List<LineItems> GetMapper()
{
using (var StreamReader = new StreamReader(#"D:\Data\Projects\dictUnitMapper.csv"))
{
using (var CsvReader = new CsvHelper.CsvReader(StreamReader, CultureInfo.InvariantCulture))
{
return
CsvReader
.GetRecords<varMapper>()
.Where(item => item.name != "#N/A")
.Where(item => item.priority != 0)
.Select(item => new LineItems()
{
variableName = item.Items,
variableUnit = item.Unit,
variableGrowthCheck = item.growth,
variableAVGCheck = item.avg,
variableSVCheck = item.svData,
longName = item.name,
priority = item.priority,
})
.ToList();
}
}
}
Here's an alternative syntax for building the return value:
return
(
from item in CsvReader.GetRecords<varMapper>()
where item.name != "#N/A"
where item.priority != 0
select new LineItems()
{
variableName = item.Items,
variableUnit = item.Unit,
variableGrowthCheck = item.growth,
variableAVGCheck = item.avg,
variableSVCheck = item.svData,
longName = item.name,
priority = item.priority,
}
).ToList();

Map one class data to another class with iteration

I have a C# project and looking for simple solution for map one class object data to list of another class object.
This is my input class
public class RatesInput
{
public string Type1 { get; set; }
public string Break1 { get; set; }
public string Basic1 { get; set; }
public string Rate1 { get; set; }
public string Type2 { get; set; }
public string Break2 { get; set; }
public string Basic2 { get; set; }
public string Rate2 { get; set; }
public string Type3 { get; set; }
public string Break3 { get; set; }
public string Basic3 { get; set; }
public string Rate3 { get; set; }
}
This is my another class structure
public class RateDetail
{
public string RateType { get; set; }
public decimal Break { get; set; }
public decimal Basic { get; set; }
public decimal Rate { get; set; }
}
it has a object like below. (For easiering the understanding, I use hardcoded values and actually values assign from a csv file)
RatesInput objInput = new RatesInput();
objInput.Type1 = "T";
objInput.Break1 = 100;
objInput.Basic1 = 50;
objInput.Rate1 = 0.08;
objInput.Type2 = "T";
objInput.Break2 = 200;
objInput.Basic2 = 50;
objInput.Rate2 = 0.07;
objInput.Type3 = "T";
objInput.Break3 = 500;
objInput.Basic3 = 50;
objInput.Rate3 = 0.06;
Then I need to assign values to "RateDetail" list object like below.
List<RateDetail> lstDetails = new List<RateDetail>();
//START Looping using foreach or any looping mechanism
RateDetail obj = new RateDetail();
obj.RateType = //first iteration this should be assigned objInput.Type1, 2nd iteration objInput.Type2 etc....
obj.Break = //first iteration this should be assigned objInput.Break1 , 2nd iteration objInput.Break2 etc....
obj.Basic = //first iteration this should be assigned objInput.Basic1 , 2nd iteration objInput.Basic2 etc....
obj.Rate = //first iteration this should be assigned objInput.Rate1, 2nd iteration objInput.Rate2 etc....
lstDetails.Add(obj); //Add obj to the list
//END looping
Is there any way to convert "RatesInput" class data to "RateDetail" class like above method in C#? If yes, how to iterate data set?
Try this:
public class RatesList : IEnumerable<RateDetail>
{
public RatesList(IEnumerable<RatesInput> ratesInputList)
{
RatesInputList = ratesInputList;
}
private readonly IEnumerable<RatesInput> RatesInputList;
public IEnumerator<RateDetail> GetEnumerator()
{
foreach (var ratesInput in RatesInputList)
{
yield return new RateDetail
{
RateType = ratesInput.Type1,
Break = Convert.ToDecimal(ratesInput.Break1, new CultureInfo("en-US")),
Basic = Convert.ToDecimal(ratesInput.Basic1, new CultureInfo("en-US")),
Rate = Convert.ToDecimal(ratesInput.Rate1, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type2,
Break = Convert.ToDecimal(ratesInput.Break2),
Basic = Convert.ToDecimal(ratesInput.Basic2),
Rate = Convert.ToDecimal(ratesInput.Rate2, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type3,
Break = Convert.ToDecimal(ratesInput.Break3),
Basic = Convert.ToDecimal(ratesInput.Basic3),
Rate = Convert.ToDecimal(ratesInput.Rate3, new CultureInfo("en-US"))
};
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And use:
var list = new RatesList(new List<RatesInput>() { objInput });
foreach (var item in list)
{
Console.WriteLine(item.Basic);
}
You can use Reflection to get the properties info like this:
var props = objInput.GetType().GetProperties();
var types = props.Where(x => x.Name.StartsWith("Type"))
.Select(x => x.GetValue(objInput)).ToList();
var breaks = props.Where(x => x.Name.StartsWith("Break"))
.Select(x => x.GetValue(objInput)).ToList();
var basics = props.Where(x => x.Name.StartsWith("Basic"))
.Select(x => x.GetValue(objInput)).ToList();
var rates = props.Where(x => x.Name.StartsWith("Rate"))
.Select(x => x.GetValue(objInput)).ToList();
List<RateDetail> lstDetails = new List<RateDetail>();
for (int i = 0; i < types.Count; i++)
{
lstDetails.Add(new RateDetail
{
RateType = types[i].ToString(),
Break = Convert.ToDecimal(breaks[i]),
Basic = Convert.ToDecimal(basics[i]),
Rate = Convert.ToDecimal(rates[i])
});
}

return multiple reader.cast<>

All I want to do is return multiple reader.cast<> so that i can use 2 sqlcommands.
var first =reader.Cast<IDataRecord>().Select(x => new LocationInfo()
{
Names = x.GetString(0),
Values = Math.Round(x.GetDouble(1), 2).ToString("#,##0.00"),
ValuesDouble = x.GetDouble(1)
}).ToList();
reader.NextResult();
var second=reader.Cast<IDataRecord>().Select(x => new LocationInfo()
{
Names2 = x.GetString(0),
Values2 = Math.Round(x.GetDouble(1), 2).ToString("#,##0.00"),
ValuesDouble2 = x.GetDouble(1)
}).ToList();
All I want to do is return var first and var second. Please help :(
I'm using this Location.cs for parameters:
namespace MVCRealtime
{
public class LocationInfo
{
public string Names { get; set; }
public string Values { get; set; }
public double ValuesDouble { get; set; }
public string Names2 { get; set; }
public string Values2 { get; set; }
public double ValuesDouble2 { get; set; }
}
}
public static class ReaderHelper
{
public static IEnumerable<TElem> GetData<TElem>(this IDataReader reader, Func<IDataRecord, TElem> buildObjectDelegat)
{
while (reader.Read())
{
yield return buildObjectDelegat(reader);
}
}
}
// ...
var result = reader.GetData(x => new LocationInfo()
{
Names = x.GetString(0),
Values = Math.Round(x.GetDouble(1), 2).ToString("#,##0.00"),
ValuesDouble = x.GetDouble(1)
}).Take(2);
So you get 1st var in 1st element of the result and 2nd var in 2nd element.

How to do Cascading Include in LiteDB

here is example on how to store cross-referenced entities in LiteDB. LiteDB stores the cross-referenced entities perfectly fine, but problem comes when I am trying to find/load entities back. My goal is NOT ONLY the requested entity but also referenced ones. There is quick tutorial section "DbRef for cross references" on LiteDB webpage how one can realize it. LiteDB has "Include" option (which is called before "FindAll") which says which referenced entities must be loaded as well. I am trying to achieve it in this code example but with no results, i.e, the code raises Exception("D_Ref") meaning "D_Ref" reference is not loaded:
namespace _01_simple {
using System;
using LiteDB;
public class A {
public int Id { set; get; }
public string Name { set; get; }
public B B_Ref { set; get; }
}
public class B {
public int Id { set; get; }
public string Name { set; get; }
public C C_Ref { set; get; }
}
public class C {
public int Id { set; get; }
public string Name { set; get; }
public D D_Ref { set; get; }
}
public class D {
public int Id { set; get; }
public string Name { set; get; }
}
class Program {
static void Main(string[] args) {
test_01();
}
static string NameInDb<T>() {
var name = typeof(T).Name + "s";
return name;
}
static void test_01() {
if (System.IO.File.Exists(#"MyData.db"))
System.IO.File.Delete(#"MyData.db");
using (var db = new LiteDatabase(#"MyData.db")) {
var As = db.GetCollection<A>(NameInDb<A>());
var Bs = db.GetCollection<B>(NameInDb<B>());
var Cs = db.GetCollection<C>(NameInDb<C>());
var Ds = db.GetCollection<D>(NameInDb<D>());
LiteDB.BsonMapper.Global.Entity<A>().DbRef(x => x.B_Ref, NameInDb<B>());
LiteDB.BsonMapper.Global.Entity<B>().DbRef(x => x.C_Ref, NameInDb<C>());
LiteDB.BsonMapper.Global.Entity<C>().DbRef(x => x.D_Ref, NameInDb<D>());
var d = new D { Name = "I am D." };
var c = new C { Name = "I am C.", D_Ref = d };
var b = new B { Name = "I am B.", C_Ref = c };
var a = new A { Name = "I am A.", B_Ref = b };
Ds.Insert(d);
Cs.Insert(c);
Bs.Insert(b);
As.Insert(a);
}
using (var db = new LiteDatabase(#"MyData.db")) {
var As = db.GetCollection<A>(NameInDb<A>());
var all_a = As
.Include(x => x.B_Ref)
.FindAll();
foreach (var a in all_a) {
if (a.B_Ref == null)
throw new Exception("B_Ref");
if (a.B_Ref.C_Ref == null)
throw new Exception("C_Ref");
if (a.B_Ref.C_Ref.D_Ref == null)
throw new Exception("D_Ref");
}
}
}
}}
after small research I've resolved the issue simply by adding extra "Include" parameterize by "x => x.B_Ref.C_Ref" lambda where x.B_Ref.C_Ref is a path in hierarchy of references:
var all_a = As
.Include(x => x.B_Ref)
.Include(x => x.B_Ref.C_Ref)
.FindAll();
Here is complete example
namespace _01_simple {
using System;
using LiteDB;
public class A {
public int Id { set; get; }
public string Name { set; get; }
public B B_Ref { set; get; }
}
public class B {
public int Id { set; get; }
public string Name { set; get; }
public C C_Ref { set; get; }
}
public class C {
public int Id { set; get; }
public string Name { set; get; }
public D D_Ref { set; get; }
}
public class D {
public int Id { set; get; }
public string Name { set; get; }
}
class Program {
static void Main(string[] args) {
test_01();
}
static string NameInDb<T>() {
var name = typeof(T).Name + "s";
return name;
}
static void test_01() {
if (System.IO.File.Exists(#"MyData.db"))
System.IO.File.Delete(#"MyData.db");
using (var db = new LiteDatabase(#"MyData.db")) {
var As = db.GetCollection<A>(NameInDb<A>());
var Bs = db.GetCollection<B>(NameInDb<B>());
var Cs = db.GetCollection<C>(NameInDb<C>());
var Ds = db.GetCollection<D>(NameInDb<D>());
LiteDB.BsonMapper.Global.Entity<A>().DbRef(x => x.B_Ref, NameInDb<B>());
LiteDB.BsonMapper.Global.Entity<B>().DbRef(x => x.C_Ref, NameInDb<C>());
LiteDB.BsonMapper.Global.Entity<C>().DbRef(x => x.D_Ref, NameInDb<D>());
var d = new D { Name = "I am D." };
var c = new C { Name = "I am C.", D_Ref = d };
var b = new B { Name = "I am B.", C_Ref = c };
var a = new A { Name = "I am A.", B_Ref = b };
Ds.Insert(d);
Cs.Insert(c);
Bs.Insert(b);
As.Insert(a);
}
using (var db = new LiteDatabase(#"MyData.db")) {
var As = db.GetCollection<A>(NameInDb<A>());
var all_a = As
.Include(x => x.B_Ref)
.Include(x => x.B_Ref.C_Ref)
.Include(x => x.B_Ref.C_Ref.D_Ref)
.FindAll();
foreach (var a in all_a) {
if (a.B_Ref == null)
throw new Exception("B_Ref");
if (a.B_Ref.C_Ref == null)
throw new Exception("C_Ref");
if (a.B_Ref.C_Ref.D_Ref == null)
throw new Exception("D_Ref");
}
}
}
}}
I hope it saves someone's time.
Update: LiteDB author says there is no support for Cascading Include. But it is planned in the next version (see issue). Consider, once, let say, B_Ref is a Lite of B, then there is no mechanism to force deeper Include.

How can I create set contain id record in first set equal id record in second set?

In database I have two tables:
public partial class PersonOne
{
public int id { get; set; }
public string name { get; set; }
public string surname { get; set; }
}
public partial class PersonTwo
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
}
I would like to fill my set:
public class PersonOnePersonTwo
{
public int PersonOneId { get; set; }
public int PersonTwoId { get; set; }
}
where PersonOne.name == PersonTwo.firstname && PersonOne.surname == PersonTwo.lastname but I have no idea how I can do that - because below code isn't efficient and is so slow:
List<PersonOne> personOneList = new List<PersonOne>();
List<PersonTwo> personTwoList = new List<PersonTwo>();
List<PersonOnePersonTwo> personOnePersonTwoList = new List<PersonOnePersonTwo>();
foreach (PersonOne personOne in personOneList)
{
foreach(PersonTwo personTwo in personTwoList.Where(x => x.firstname == personOne.name && x.lastname == personOne.surname).ToList())
{
personOnePersonTwoList.Add(new PersonOnePersonTwo
{
PersonOneId = personOne.id,
PersonTwoId = personTwo.id
});
}
};
Try this:
var result = personOneList.Join
(
personTwoList,
person1 => new { Key1 = person1.Name, Key2 = person1.Surname },
person2 => new { Key1 = person2.FirstName, Key2 = person2.LastName },
(person1, person2) => new PersonOnePersonTwo { PersonOneId = person1.Id, PersonTwoId = person2.Id }
).ToList();
I would go with:
var personOnePersonTwoList = new List<PersonOnePersonTwo>();
foreach (var personOne in personOneList)
{
personOnePersonTwoList = personTwoList.Where(x => x.firstname.Equals(personOne.name, StringComparison.OrdinalIgnoreCase) &&
x.lastname.Equals(personOne.surname, StringComparison.OrdinalIgnoreCase))
.Select(x => new PersonOnePersonTwo {PersonOneId = personOne.id, PersonTwoId = x.id}).ToList();
};
As a side note: it's more convinient to use Equals when comparing strings.

Categories

Resources