Adding data from one list to another using linq - c#

I need to populate a dropdown in my UI and hence added List object to the view model in my c# application. I am fetching the data in my controller code for the dropdown. What's the best way to assign data to the viewmodel object. Is linq an option?
I basically need to assign fundclasses to fundTrackRecord.FundClass
The main Viewmodel:
public class FundPerformanceVM
{
public FundPerformanceVM()
{
TrackRecord = new List<TrackRecordVM>();
}
public int FundId { get; set; }
public string FundName { get; set; }
public List<FundClassVM> FundClass { get; set; }
public string BenchmarkName1 { get; set; }
public string BenchmarkName2 { get; set; }
public List<TrackRecordVM> TrackRecord { get; set; }
public List<Tuple<string, string, string>> FundStatistics { get; set; }
}
public class FundClassVM
{
public int FundClassId { get; set; }
public string FundClass { get; set; }
}
Controller code:
var service = GetViewService<V_LEGAL_FUND_CLASS_SUMMARY>();
foreach (KeyValuePair<int, IEnumerable<FUND_PERFORMANCE>> entry in allPerformance)
{
var fundClasses = service.GetAll().Where(x => x.FUND_ID == entry.Key).Select(x => new { x.LEGAL_FUND_CLASS_ID, x.LEGAL_FUND_CLASS}).ToList();
var fundTrackRecord = new FundPerformanceVM();
fundTrackRecord.FundClass = ??;

If I understood correctly the structure of your model, you can try this:
fundTrackRecord.FundClass = fundClasses.Select(fc => new FundClassVM
{
FundClassId = fc.LEGAL_FUND_CLASS_ID,
FundClass = fc.LEGAL_FUND_CLASS
}).ToList();
You can also do this directly, replacing the code:
var fundClasses = service.GetAll().Where(x => x.FUND_ID == entry.Key).Select(x => new { x.LEGAL_FUND_CLASS_ID, x.LEGAL_FUND_CLASS}).ToList();
var fundTrackRecord = new FundPerformanceVM();
With:
var fundTrackRecord = new FundPerformanceVM();
fundTrackRecord.FundClass = service.GetAll().
Where(x => x.FUND_ID == entry.Key).
Select(fc => new FundClassVM
{
FundClassId = fc.LEGAL_FUND_CLASS_ID,
FundClass = fc.LEGAL_FUND_CLASS
}).ToList();

Related

How to use lambda expression to access correct data type?

I am using lambda expression to access values with data type, but the problem I have data type for Time as Time(7) on my local database and using Entity Framework. On my model this data type is define as DateTime.
How do I now access this data type to be time?
This is my code:
public List GetIncident_Details()
{
Entities incident = new Entities();
List result = new List();
var c_incident = incident.Incident_Template.Select(c => c).ToList();
if (c_incident != null && c_incident.Count() > 0)
{
foreach (var cData in c_incident)
{
Incident_DropDown model = new Incident_DropDown();
model.Title = cData.Title;
model.Description = cData.Description;
model.Date_Occurred = cData.Date_Occurred;
// How do I change this to have access?
// It's complaining about the data type object being set to a string?
model.Time = cData.Time;
model.Assignment_Group = cData.Assignment_Group;
model.Reported_CI = cData.Reported_CI;
result.Add(model);
}
}
return result;
}
public class Incident_DropDown
{
public string Title { get; set; }
public string Description { get; set; }
public string Date_Occurred { get; set; }
public DateTime Time { get; set; } // Time
public string Assignment_Group { get; set; }
public string Reported_CI { get; set; }
}
Took some advice from #alexey-rumyantsev, then had to test my code by interrogating model data type for Time it was Date Time, then change to Timespan. While testing this data type compare to my local database record and it was passing correct vales when debugging.
// Model name
public class Incident_DropDown
{
public string Title { get; set; }
public string Description { get; set; }
public string Date_Occured { get; set; }
public TimeSpan Time { get; set; } // had to change to work
public string Assignment_Group { get; set; }
public string Reported_CI { get; set; }
}
// Controller
public List<Incident_DropDown> GetIncident_Details()
{
Entities incident = new Entities();
List<Incident_DropDown> result = new List<Incident_DropDown>();
var c_incident = incident.Incident_Template.Select(c => c).ToList();
if (c_incident != null && c_incident.Count() > 0)
{
foreach (var cData in c_incident)
{
Incident_DropDown model = new Incident_DropDown();
model.Title = cData.Title;
model.Description = cData.Description;
model.Date_Occured = cData.Date_Occured;
model.Time = cData.Time; // This here enable to pass correct time as per database record
model.Assignment_Group = cData.Assignment_Group;
model.Reported_CI = cData.Reported_CI;
result.Add(model);
}
}
return result;
}

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])
});
}

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.

Linq from list objects into one object with a list property

Im trying to use Linq to select the property ProductColor from a List of MyObject into the property AllProductColors
public class MyObject
{
public string ImgUrl { get; set; }
public string ProductName { get; set; }
public string ProductColor { get; set; }
}
public class ObjectToSelectInto
{
public string ImgUrl { get; set; }
public string ProductName { get; set; }
public List<string> AllProductColors { get; set; }
}
//*** CREATING EXAMPLE ***///
List<MyObject> MyObjectList = new List<MyObject>();
ObjectToSelectInto destinationObject = new ObjectToSelectInto();
//I can do it like this, but then I
// would have to do this for every list item, not good!
destinationObject.AllProductColors =
MyObjectList.Select(x => x.ProductColor).toList();
//*** This fails ***///
destinationObject = MyObjectList.Select( x =>
new destinationObject {
AllProductColors = x.ProductColor.ToList(),
ImgUrl = x.ImgUrl.First().toString(),
ProductName = x.ProductName .First().toString()
}
I want it to be like this.
destinationObject has a list with elements where one color equals one element.
You just need to put your first query that you tried into second like this:
destinationObject = MyObjectList.Select(x =>
new ObjectToSelectInto()
{
AllProductColors = MyObjectList.Select(y => y.ProductName).ToList(),
ImgUrl = x.ImgUrl,
ProductName = x.ProductName
}).First();

RavenDb how do I reduce group values into collection in reduce final result?

I hope it's more clear what I want to do from the code than the title. Basically I am grouping by 2 fields and want to reduce the results into a collection all the ProductKey's constructed in the Map phase.
public class BlockResult
{
public Client.Names ClientName;
public string Block;
public IEnumerable<ProductKey> ProductKeys;
}
public Block()
{
Map = products =>
from product in products
where product.Details.Block != null
select new
{
product.ClientName,
product.Details.Block,
ProductKeys = new List<ProductKey>(new ProductKey[]{
new ProductKey{
Id = product.Id,
Url = product.Url
}
})
};
Reduce = results =>
from result in results
group result by new {result.ClientName, result.Block} into g
select new BlockResult
{
ClientName = g.Key.ClientName,
Block = g.Key.Block,
ProductKeys = g.SelectMany(x=> x.ProductKeys)
};
}
I get some weird System.InvalidOperationException and a source code dump where basically it is trying to initialize the list with an int (?).
If I try replacing the ProductKey with just IEnumerable ProductIds (and make appropriate changes in the code). Then the code runs but I don't get any results in the reduce.
You probably don't want to do this. Are you really going to need to query in this manner? If you know the context, then you should probably just do this:
var q = session.Query<Product>()
.Where(x => x.ClientName == "Joe" && x.Details.Block == "A");
But, to answer your original question, the following index will work:
public class Products_GroupedByClientNameAndBlock : AbstractIndexCreationTask<Product, Products_GroupedByClientNameAndBlock.Result>
{
public class Result
{
public string ClientName { get; set; }
public string Block { get; set; }
public IList<ProductKey> ProductKeys { get; set; }
}
public class ProductKey
{
public string Id { get; set; }
public string Url { get; set; }
}
public Products_GroupedByClientNameAndBlock()
{
Map = products =>
from product in products
where product.Details.Block != null
select new {
product.ClientName,
product.Details.Block,
ProductKeys = new[] { new { product.Id, product.Url } }
};
Reduce = results =>
from result in results
group result by new { result.ClientName, result.Block }
into g
select new {
g.Key.ClientName,
g.Key.Block,
ProductKeys = g.SelectMany(x => x.ProductKeys)
};
}
}
When replicating I get the same InvalidOperationException, stating that it doesn't understand the index definition (stack trace omitted for brevity).
Url: "/indexes/Keys/ByNameAndBlock"
System.InvalidOperationException: Could not understand query:
I'm still not entirely sure what you're attempting here, so this may not be quite what you're after, but I managed to get the following working. In short, Map/Reduce deals in anonymous objects, so strongly typing to your custom types makes no sense to Raven.
public class Keys_ByNameAndBlock : AbstractIndexCreationTask<Product, BlockResult>
{
public Keys_ByNameAndBlock()
{
Map = products =>
from product in products
where product.Block != null
select new
{
product.Name,
product.Block,
ProductIds = product.ProductKeys.Select(x => x.Id)
};
Reduce = results =>
from result in results
group result by new {result.Name, result.Block}
into g
select new
{
g.Key.Name,
g.Key.Block,
ProductIds = g.SelectMany(x => x.ProductIds)
};
}
}
public class Product
{
public Product()
{
ProductKeys = new List<ProductKey>();
}
public int ProductId { get; set; }
public string Url { get; set; }
public string Name { get; set; }
public string Block { get; set; }
public IEnumerable<ProductKey> ProductKeys { get; set; }
}
public class ProductKey
{
public int Id { get; set; }
public string Url { get; set; }
}
public class BlockResult
{
public string Name { get; set; }
public string Block { get; set; }
public int[] ProductIds { get; set; }
}

Categories

Resources