Returning a List<> inheritance C# - c#

class cuentaBancaria
{
public cuentaBancaria()
{
}
public cuentaBancaria(string nombreCliente, string numCuenta, double tipoInteres, double saldo)
{
this.nombreCliente = nombreCliente;
this.numCuenta = numCuenta;
this.tipoInteres = tipoInteres;
this.saldo = saldo;
}
public string nombreCliente { get; set; }
public string numCuenta { get; set; }
public double tipoInteres { get; set; }
public double saldo { get; set; }
public static List<cuentaBancaria> cuentas = new List<cuentaBancaria>()
{
new cuentaBancaria ("John Doe", "123456", 1.5, 159),
new Tarjeta ("John Doe", "123456" , 1.5, 159, "123456789012", "John Doe", TipoTarjeta.CREDITO)
};
}
TipoTarjeta:
enum TipoTarjeta
{
CREDITO,
DEBITO,
MONEDERO,
FINANCIACION
}
Tarjeta:
class Tarjeta : cuentaBancaria
{
public Tarjeta()
{
}
public Tarjeta(string nombreCliente, string numCuenta, double tipoInteres, double saldo, string numTarjeta, string nombre, TipoTarjeta tipoTarjeta)
{
base.nombreCliente = nombreCliente;
base.numCuenta = numCuenta;
base.tipoInteres = tipoInteres;
base.saldo = saldo;
this.numTarjeta = numTarjeta;
this.nombre = nombre;
this.tipoTarjeta = tipoTarjeta;
}
public string numTarjeta { get; set; }
public string nombre { get; set; }
public TipoTarjeta tipoTarjeta { get; set; }
}
I want to return the elements that has a TipoTarjeta.XXX but when I try the
cuentas.Where(c => c.tipoTarjeta == tipo)
I get the error that is an element of the child (Tarjeta) not cuentaBancaria.
How can I only get those elements with that type?

You have a type mismatch.
Your function is declared such that it returns List<cuentaBancaria>, but Where is a LINQ extension method that returns an IEnumerable<cuentBancaria>.
To resolve your issue, add a call to the ToList() extension method as follows:
cuentas.Where(c => c.tipoTarjeta == tipo).ToList()
UPDATE
I copied your code to VSCode and this version of Main works for me. From what I could tell, you needed to reference cuentas through cuentaBancaria; also, the property you were referencing in the Where clause was incorrect, based on the class definition.
public static void Main()
{
var tipo = 3.15;
var result = cuentaBancaria.cuentas.Where(c => c.tipoInteres == tipo).ToList();
foreach (var item in result)
{
Console.WriteLine(item.tipoInteres);
}
}

You first need to filter the list to only the types of Tarjeta, and then you can filter by properties of Tarjeta. You can do this using .OfType<T>() in LINQ:
cuentas.OfType<Tarjeta>().Where(c => c.tipoTarjeta == tipo)

Related

Need help using Linq to transform a list into a different list

Lets say I have a list that contains 1 record:
[
{
"AccountNumber": 1234,
"eDocConfirms": true,
"eDocStatements": true,
"eDocTaxforms": false
}
]
This list is a strongly typed object with these properties:
public int AccountNumber { get; set; }
public bool? eDocConfirms { get; set; }
public bool? eDocStatements { get; set; }
public bool? eDocTaxforms { get; set; }
Using LINQ, I'd like to turn it into a list that looks like this:
[
{
"AccountNumber": 1234,
"EDocumentTypeName ": "Confirms"
},
{
"AccountNumber": 1234,
"EDocumentTypeName": "Statements"
}
]
This new list will a list of a different type:
public class DeliveryPreference
{
public int AccountNumber { get; set; }
public string EDocumentTypeName { get; set; }
}
Note that Taxforms was not included in the new list because it was set to false in the first list.
I know I could easily do this with some loops, but I would prefer using LINQ.
I understand that Stack Overflow prefers that I show what I have tried, but I am having trouble wrapping my brain around this.
For this case I would use additional function
public static IEnumerable<string> GetTrueProperties(Data t)
{
if (t.eDocConfirms == true) yield return "Confirms";
if (t.eDocStatements == true) yield return "Statements";
if (t.eDocTaxForms == true) yield return "Tax";
}
simply because it is an object and not a dictionary; else you could dynamically select properties which are true(or you could use reflection, but I think it would be too much here, since you have strongly typed object).
then it would look like
var list = new List<Data> {
new Data
{
AccountNumber = 1,
eDocConfirms = true,
eDocStatements = true,
eDocTaxForms = false
}
};
list.SelectMany(item => GetTrueProperties(item).Select(p => new DeliveryPreference
{
AccountNumber = item.AccountNumber,
EDocumentTypeName = p
}));
This is very ugly code, but it works. It should be easy to comprehend. Reflection can be extracted to a new function.
using System;
using System.Linq;
public class Program
{
public class Account {
public int AccountNumber { get; set; }
public bool? eDocConfirms { get; set; }
public bool? eDocStatements { get; set; }
public bool? eDocTaxforms { get; set; }
}
public class DeliveryPreference
{
public int AccountNumber { get; set; }
public string EDocumentTypeName { get; set; }
}
public static void Main()
{
var acc = new Account {
AccountNumber = 10,
eDocConfirms = true,
eDocStatements = false,
eDocTaxforms = true
};
var transformed = acc.GetType()
.GetProperties()
.Where(p => p.PropertyType == typeof(bool?)
&& ((bool?)p.GetValue(acc)).HasValue
&& ((bool?)p.GetValue(acc)).Value)
.Select(p => new DeliveryPreference {
AccountNumber = acc.AccountNumber,
EDocumentTypeName = p.Name.Substring(4)
});
foreach (var t in transformed) {
Console.WriteLine(t.AccountNumber);
Console.WriteLine(t.EDocumentTypeName);
}
}
}

Dapper MultiMapping not working

I'm trying to create a List of object Work using Dapper to do the mapping.
This is the code:
public class Work
{
public int id { get; set; }
public int id_section { get; set; }
public decimal price { get; set; }
public Model id_model { get; set; }
public Type id_type { get; set; }
}
class Model
{
public int id_model { get; set; }
public string Name { get; set; }
}
class Type
{
public int id_type { get; set; }
public string Name { get; set; }
}
public List<Work> GetListOfWork(int idList)
{
using (DatabaseConnection db = new DatabaseConnection()) //return a connection to MySQL
{
var par = new {Id = idList};
const string query = "SELECT id,id_section,price,id_model,id_type FROM table WHERE id_section = #Id";
return db.con.Query<Work, Model, Type, Work>(query,
(w, m, t) =>
{
w.id_model = m;
w.id_type = t;
return w;
}, par, splitOn: "id_model,id_type").ToList();
}
}
It doesn't give me any error but id_model and id_type in my the returned List are always empty (The object are created but all the fields are empty or null), other fields are mapped correctly.
Any clue ?
You need to add yourself the joins in the query string
Probably it is something like this
var par = new {Id = idList};
const string query = #"SELECT w.id,w.id_section,w.price,
m.id_model, m.Name, t.id_type, t.Name
FROM work w INNER JOIN model m on w.id_model = m.id_model
INNER JOIN type t on w.id_type = t.id_type
WHERE w.id_section = #Id";
return db.con.Query<Work, Model, Type, Work>(query,
(w, m, t) =>
{
w.id_model = m;
w.id_type = t;
return w;
}, par, splitOn: "id_model,id_type").ToList();

how to get Json nested properties to primary one

I have below scenario:
This is my class structure :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public System.Collections.ObjectModel.Collection<Likes> Likes { get; set; }
}
public class Likes
{
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
}
When I serialize object of User class then it will generate the below json string :
{"FirstName":"Naresh",
"LastName":"Parmar",
"Likes": [{"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"}]
}
I want to generate above json string like below:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
I want the nested properties as primary one.
Any help would be appreciated.
Thanks in advance..
EDIT:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket,Chess,Football",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
It's really bad practice, since the code i'll post bellow doesn't have great maintainability, however if that's what you looking for, you can use this. Another class that have the format that you'd like, and have a method that adds a list of likes to the format you've required. That the class you should serialize to JSON:
class NestedUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
public void AddLikes(System.Collections.ObjectModel.Collection<Likes> likes)
{
foreach (Likes like in likes)
{
Sport += like.Sport + ",";
Music += like.Music + ",";
Food += like.Food + ",";
Place += like.Place + ",";
}
if (Sport != string.Empty)
{
Sport = Sport.Substring(0, Sport.Length - 1);
}
if (Music != string.Empty)
{
Music = Music.Substring(0, Music.Length - 1);
}
if (Food != string.Empty)
{
Food = Food.Substring(0, Food.Length - 1);
}
if (Place != string.Empty)
{
Place = Place.Substring(0, Place.Length - 1);
}
}
}
Since it's not only limited to Likes objects I'd suggest using dynamic objects. So the User class I propose is as follows:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public dynamic Details { get; set; }
public User()
{
Details = new ExpandoObject();
}
public void AddSingleDetail(string key, string value)
{
var dict = this.Details as IDictionary<string, Object>;
if (dict.ContainsKey(key))
{
dict[key] += "," + value;
}
else
{
dict[key] = value;
}
}
public void AddDetails(object detailsObject)
{
var type = detailsObject.GetType();
foreach (var prop in type.GetProperties())
{
AddSingleDetail(prop.Name, prop.GetValue(detailsObject).ToString());
}
}
}
You can use it for adding single proerpties or adding an object as a whole. I used reflection to get all the property name and values and add them to the user details.
Sample usage:
static void Main(string[] args)
{
var user1 = new User() { FirstName = "Homer", LastName = "Simpson" };
user1.AddSingleDetail("Sport", "Bowling");
user1.AddSingleDetail("Sport", "Sleeping");
user1.AddSingleDetail("Food", "Donut");
user1.AddSingleDetail("Music", "Rock");
string flattenedHomer1 = ConvertUserToFlattenedJson(user1);
var user2 = new User() { FirstName = "Homer", LastName = "Simpson" };
var likes1 = new Likes() { Food = "Donut", Music = "Rock", Place = "Springfield", Sport = "Bowling" };
var likes2 = new Likes() { Food = "Steaks", Music = "Metal", Place = "Evergreen Terrace", Sport = "Sleeping" };
var proStuff = new ProfessionalStuff() { Title = "Boss" };
user2.AddDetails(likes1);
user2.AddDetails(likes2);
user2.AddDetails(proStuff);
string flattenedHomer2 = ConvertUserToFlattenedJson(user2);
}
And the method performing the JSON conversion is:
public static string ConvertUserToFlattenedJson(User u)
{
dynamic flatUser = new ExpandoObject();
flatUser.FirstName = u.FirstName;
flatUser.LastName = u.LastName;
var dict = u.Details as IDictionary<string, Object>;
foreach (var like in dict)
{
((IDictionary<string, Object>)flatUser)[like.Key] = like.Value;
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(flatUser);
return json;
}
In my sample above user2 is converted to the following JSON string which I believe is what you are looking for:
{
"FirstName": "Homer",
"LastName": "Simpson",
"Sport": "Bowling,Sleeping",
"Music": "Rock,Metal",
"Food": "Donut,Steaks",
"Place": "Springfield,Evergreen Terrace",
"Title": "Boss"
}
While concatenating strings you can check for null or duplicate values. I didn't handle that part.
For the sake of completeness, here's the ProfessionalStuff class I made up:
public class ProfessionalStuff
{
public string Title { get; set; }
}
Hope this helps.

Nested List Order In C#

I have a custom list called ServiceFormFields and it has a List property named ChildrenTables.
I want to order descending by ChildrenTables' names
var fields = activeForm.ServiceFormFields.OrderBy (o =>
o.ChildrenTables.OrderBy(c=>c)).ToList();
but it does not work.
I want to order ServiceFormFields list according to its children. Maybe I should do with GroupBy..
So, for example...
ServiceFormFields has FieldName property.. and Children is a List of String
FieldName = Matter, Children = Version
FieldName = Client, Children = Matter
FieldName = Status, Children = Null
FieldName = Version, Children = Null (but has parents, it is Matter)
so and I want to order like:
2,1,3,4
because Client is the on highest level, second is Matter, third one is Version because Matter is its parent, and final is Status, because it does not have any dependency.
Edit: This is structure of the class
public class ServiceForm
{
public List<ServiceFormField> ServiceFormFields { get; set; }
public string Id { get; set; }
public bool IsDefaultPrimary { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string Type { get; set; }
}
public class ServiceFormField
{
public FormProperty FormField {get;set;}
public bool IsVisible { get;set;}
public List<string> ParentTables { get; set; }
public bool HasChildren { get; set; }
public List<string> ChildrenTables { get; set; }
}
public partial class FormProperty
{
private string NameField;
private string SQLInfoField;
...
}
NameField contains Client, Matter, Version..
I don't know if this is what you want, but here's a solution with the least bits of code needed.
I just transformed all the Childrens into a single string, and then the order by compares against them.
This is certainly not the most performance-wise solution, if this matters.
here's a sample:
static void Main(string[] args)
{
ServiceForm sf = new ServiceForm();
sf.ServiceFormFields = new List<ServiceFormField>
{
new ServiceFormField { ChildrenTables = new List<string> { "a", "b", "c"}},
new ServiceFormField { ChildrenTables = new List<string> { "tra la la", "xxx"}},
new ServiceFormField { ChildrenTables = new List<string> { "TTTTT" }},
new ServiceFormField { ChildrenTables = new List<string> { "123455", "8157125", "1763123"}},
new ServiceFormField { ChildrenTables = new List<string> { " ", " ", " ", " "}}
};
var ordered= sf.ServiceFormFields.OrderByDescending(f => string.Join(",", f.ChildrenTables)).ToList();
foreach(ServiceFormField sff in ordered)
{
foreach(string s in sff.ChildrenTables)
{
Console.WriteLine(s);
}
}
}
Output:
There are two ways, first you can use the List.Sort function with the signature Comparison like:
activeForm.ServiceFormFields.Sort(new Comparison<ServiceFormField>((e1,e2)=>Compare(e1, e2)));
private static int Compare(ServiceFormField e1, ServiceFormField e2)
{
//Do your logic here
}
in this case you will have an inplace sort.
or use the linq orderby function with the signature to KeySelector, an IComparer and implement an IComparer like that
var result = activeForm.ServiceFormFields.OrderBy(e => e, new ServiceFormFieldComparer());
public class ServiceFormFieldComparer : IComparer<ServiceFormField>
{
private int Compare(ServiceFormField e1, ServiceFormField e2)
{
//Your logic here
}
}
in this case you will have an ordered list returned to you

JSON Parser Element not found

This is my JSON
{
"State of Origin 2014":{
"1471137":{
"EventID":1471137,
"ParentEventID":1471074,
"MainEvent":"State Of Origin Series 2014",
"Competitors":{
"ActiveCompetitors":3,
"Competitors":[
{
"Team":"New South Wales (2 - 1)",
"Win":"2.15",
},
{
"Team":"New South Wales (3 - 0)",
"Win":"3.05",
},
{
"Team":"Queensland (2 - 1)",
"Win":"3.30",
}
],
"TotalCompetitors":3,
"HasWinOdds":true
},
"EventStatus":"Open",
"IsSuspended":false,
"AllowBets":true
},
"3269132":{
"EventID":3269132,
"ParentEventID":0,
"MainEvent":"New South Wales v Queensland",
"Competitors":{
"Margin1Low":1,
"Competitors":[
{
"Name":"New South Wales",
"Win":"1.60",
},
{
"Name":"Queensland",
"Win":"2.35",
}
],
"HasWinOdds":true,
"TotalOddsColumns":2,
"MarketCount":1,
"PerformVideo":false
},
"EventStatus":"Open",
"IsSuspended":false,
"AllowBets":true
}
}
}
I am using JSON.Net and everything is working fine but in some of my data some element fields are missing for example i am getting Team element inside Competitors as
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"]
But in some data Team element is missing and i want to grap Name Element so i am getting Object reference not set to an instance of an object. Error.
This is my code
var query =
from JProperty ev in obj.AsJEnumerable()
from JProperty evid in ev.Value.AsJEnumerable()
let value = (JObject)evid.Value
select new Person
{
EventID = (string)value["EventID"],
Description = (string)value["MainEvent"],
OutcomeDateTime = (string)value["OutcomeDateTime"],
EventStatus = (string)value["EventStatus"],
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"]
};
foreach (var b in query)
{
string description = b.Description;
string OutcomeDateTime = b.OutcomeDateTime;
IEnumerable<string> _team = b.Teams;
foreach (var teams in _team)
{
string team = teams.ToString();
}
Console.WriteLine(description);
Console.WriteLine(OutcomeDateTime);
}
How can i get Name element value if Team element does not exist ?
You can deserialize your json to concrete classes
var obj = JsonConvert.DeserializeObject < Dictionary<string, Dictionary<string,RootObject>>>(json);
public class Competitor
{
public string Team { get; set; }
public string Win { get; set; }
}
public class CompetitorsClass
{
public int ActiveCompetitors { get; set; }
public List<Competitor> Competitors { get; set; }
public int TotalCompetitors { get; set; }
public bool HasWinOdds { get; set; }
}
public class RootObject
{
public int EventID { get; set; }
public int ParentEventID { get; set; }
public string MainEvent { get; set; }
public CompetitorsClass Competitors { get; set; }
public string EventStatus { get; set; }
public bool IsSuspended { get; set; }
public bool AllowBets { get; set; }
}
BTW: What is OutcomeDateTime? there is no such field in your json.
The following will work. Use the null-coalescing operator to grab "Name" if "Team" is null. http://msdn.microsoft.com/en-us/library/ms173224.aspx
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"] ?? (string)comps["Name"]

Categories