How to write LINQ query on Generic List - c#

I have a situation where I have a generic method which accepts an object of type generic and I want to write a LINQ query on that object.
Here is an example:
Generic Method:
public static void GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
// How To Write LINQ Here to get non verified person
}
Student Class:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
Teacher Class:
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
Person Class:
public class Person<T>
{
public List<T> PersonList { get; set; }
}
Main Class:
// 1. Get Non Verified Students
var persons = new Person<Student>();
var students = new List<Student>()
{
new Student { Id = 1, Name = "Student_A", IsVerified = true },
new Student { Id = 2, Name = "Student_B", IsVerified = false },
};
persons.PersonList = new List<Student>();
persons.PersonList.AddRange(students);
GetNonNonVerifiedPersons(persons);
// 2. Get Non Verified Teachers
var persons2 = new Person<Teacher>();
var teachers = new List<Teacher>()
{
new Teacher { Id = 1, Name = "Teacher_A", IsVerified = true },
new Teacher { Id = 2, Name = "Teacher_B", IsVerified = false },
new Teacher { Id = 3, Name = "Teacher_C", IsVerified = false },
};
persons2.PersonList = new List<Teacher>();
persons2.PersonList.AddRange(teachers);
GetNonNonVerifiedPersons(persons2);

You should use interface to be able to specify the type of Teacher and Student in generic type. When you use where clause compiler is able to do the type checks at compile time.
public interface IHuman
{
string Name { get; set; }
bool IsVerified { get; set; }
}
public class Teacher : IHuman
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
public class Student : IHuman
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
And then your method should be like this. Here we have where clause that says only accept generic type TResult when implements IHuman.
public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model) where TResult : IHuman
{
return model.PersonList.Where(x => !x.IsVerified);
}
Update : I highly suggest you to make the big changes because its how it should be.
Other way which is not common and extremely slow is to check for the types at runtime.
public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
var list = model.PersonList;
var t = list.FirstOrDefault() as Teacher;
if (t != null)
{
return model.PersonList.Where(x => !(x as Teacher).IsVerified);
}
var s = list.FirstOrDefault() as Student;
if (s != null)
{
return model.PersonList.Where(x => !(s as Student).IsVerified);
}
return null;
}

May be this can do the trick:
IList<Person<TResult>> xyz = new List<Person<TResult>>();
var list = xyz.Where(a => a.GetType() == typeof(Student).IsVerified);
I didn't check it in IDE but something like this would work

Related

How to manually map a List of object to a list of DTO?

I have these:
public class FamilyHead
{
public Guid HeadId { get; set; }
public string Name { get; set; }
}
public class Citizen
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
// more properties
[ForeignKey("FamilyHead")]
public Guid HeadId { get; set; }
public virtual FamilyHead FamilyHead { get; set; }
}
public class CitizenDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
public short Age { get; set; }
public Guid HeadId
public string HeadName { get; set; }
}
I can manually map it via extension method if it is a single instance:
public static CitizenDTO ToDTO(this Citizen citizen)
{
if (citizen == null) return null;
return new CitizenDTO {
Id = citizen.Id,
Name = citizen.Name,
HeadId = citizen.HeadId,
HeadName = citizen.FamilyHead.Name
}
}
var dto = aCitizen.ToDTO();
But how to map a list of citizens? I think Select() might do the work but I only know how to do it if the model and the dto have a same structure. Like this example:
IEnumerable<int> integers = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<string> strings = integers.Select(i => i.ToString());
So how to map a list of it?
You can use Linq Select() as you used for string in your question, no need to write long extension method
IEnumerable<CitizenDTO> dto = citizens.Select(x => x.ToDTO());
I found the answer before finishing my question. Just iterate through the list and add mapped DTO to it. Silly me
// Extension method
public static IEnumerable<CitizenDTO> ToDTO(this IEnumerable<Citizen> citizens)
{
if (citizen == null) return null;
var dto = new List<CitizenDTO>();
foreach(var citizen in citizens) {
dto.Add(citizen.ToDTO());
}
return dto;
}
// How to use
IEnumerable<CitizenDTO> result = listOfCitizens.ToDTO();

How to compare object and List<> and object.value null when the value doesn't exist in list

I need to compare between my object and a list.
List contains attribute "nom_colonne", it fill by a query and the result is a list of attributes (same like my object AppareilsReparations)
For example :
if droit_utilisateur.nom_colonne = "Num_dossier"
so i keep the value in arp.num_dossier
But if i don't have this value of my list droit_utilisateur :
arp.num_dossier will be null.
I wanted to cast my object with System.Collections.IList but impossible to cast. I have an error.
public class AppareilsReparations
{
public string Num_dossier { get; set; }
//public string reference_aff { get; set; }
public int Id { get; set; }
public Guid Uid { get; set; }
public string ref_sav { get; set; }
public CodeDefaut codedefaut { get; set; }
public CodeSymptome codesymptome { get; set; }
}
public class Droits
{
public int id { get; set; }
public int utilisateur_id { get; set; }
public string nom_table { get; set; }
public string nom_colonne { get; set; }
}
AppareilsReparations arp = db.Query<AppareilsReparations>
("select * from v_appareils_reparations where ref_sav_client =#ref_sav", new { ref_sav }).SingleOrDefault();
List<Droits> droit_utilisateur = GetDroits("admin");
//var appareil = new List<AppareilsReparations>();
IList appareil = (IList)arp;
var result = droit_utilisateur.Where(x => !appareil.Contains(x.nom_colonne)).ToList();
That's cause AppareilsReparations is not a type of IList and thus your cast would always fail IList appareil = (IList)arp;. Probably you wanted to do like below; just comparing with Num_dossier field of AppareilsReparations type
var result = droit_utilisateur.Where(x => x.nom_colonne == arp.Num_dossier).ToList();
i have found my problem, i post my code for everybody :
List<Droits> droit_utilisateur = GetDroits(username);
Type myType = e.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in e.GetType().GetProperties())
{
object propValue = prop.Name;
if (droit_utilisateur.Any(s => s.nom_colonne.Contains(prop.Name/*, StringComparison.OrdinalIgnoreCase)*/) == false))
{
prop.SetValue(e, Convert.ChangeType(null, prop.PropertyType), null);
}
}
return e;

AutoMapper c# runtime mapping depending on an object property

I would like to know, how could I, with AutoMapper, Map one Dto to multiple entities.
Lemme explain.
I've got one Dto, with an enum to describe its type (to avoid having multiple dtos)
Depending on that enum (RelationType here), I would like to map it to the correct Model (Entity, what ever, it's another object that I use in database).
public class BCardDto : IMappedDto
{
public long Id { get; set; }
public BCardRelationType RelationType { get; set; }
public long RelationId { get; set; }
}
Here are is my Model base:
public class BCardModel : IMappedDto
{
public long Id { get; set; }
}
And here the derived model :
public class CardBCardModel : BCardModel
{
// ormlite, ignore that
[Reference]
public CardModel Card { get; set; }
[ForeignKey(typeof(CardModel), ForeignKeyName = "fk_bcard_card")]
public long RelationId { get; set; }
}
How do I map my Dto to the correct Model depending on the enum i've given ?
(I don't wanna use Mapper.Map everywhere but I wanna let mapper do the runtime mapping job)
Here is how I do it for the Model -> Dto
cfg.CreateMap<CardBCardModel, BCardDto>()
.ForMember(s => s.RelationType, expression => expression.UseValue(BCardRelationType.Card))
.IncludeBase<BCardModel, BCardDto>();
Tell me if I do something wrong and explain me why please :)
Thanks by advance,
Blowa.
Let's say you have a setup wherein there is a base class and 2 classes which derive the base class:
public class ModelBase
{
public string Name { get; set; }
}
public class ModelOne : ModelBase { }
public class ModelTwo : ModelBase { }
Let's also say you have a DTO with an enum as below:
public class ModelDto
{
public string Name { get; set; }
public ModelType ModelType { get; set; }
}
public enum ModelType
{
One = 1,
Two = 2
}
So now the task is: How do I map the ModelDto to either ModelOne or ModelTwo depending on the value in ModelDto.ModelType property?
Here is how:
Mapper.Initialize(cfg => cfg.CreateMap<ModelDto, ModelBase>().ConstructUsing(x =>
{
switch (x.ModelType)
{
case ModelType.One:
return new ModelOne { Name = x.Name };
case ModelType.Two:
return new ModelTwo { Name = x.Name };
default:
throw new InvalidOperationException("Unknown ModelType...");
}
}));
Usage
var dto1 = new ModelDto { ModelType = ModelType.One, Name = "ModelOne" };
var dto2 = new ModelDto { ModelType = ModelType.Two, Name = "ModelTwo" };
var one = Mapper.Map<ModelBase>(dto1);
var two = Mapper.Map<ModelBase>(dto2);
Another way to do the mapping is by using dynamic:
public class PersonDto
{
public string Name { get; set; }
}
public class StudentDto : PersonDto
{
public int studentNumber { get; set; }
}
public class EmployeDto : PersonDto
{
public string EmployeId { get; set; }
}
public class Person
{
public string Name { get; set; }
}
public class Student : Person
{
public int StudentNumber { get; set; }
}
public class Employe : Person
{
public string EmployeId { get; set; }
}
Create Map by using:
Mapper.CreateMap<StudentDto, Student>();
Mapper.CreateMap<EmployeDto, Employe>();
Do the Mapping by:
try
{
var student = MapPerson((dynamic) studentDto);
var employe = MapPerson((dynamic) employeDto);
}
catch
{
throw new InvalidOperationException("Unknown ModelType...");
}
And define two Methods
public static Student MapPerson(StudentDto studentDto)
{
return Mapper.Map<StudentDto, Student>(studentDto);
}
public static Employe MapPerson(EmployeDto employeDto)
{
return Mapper.Map<EmployeDto, Employe>(employeDto);
}
The benefit is that you don't need a key and avoid the switch statement

Linq Union of two queries throws null exception on string assignment

I have these two queries where the first one returns organization with departments and the second one returns organizations without departments and after that I use Union() for my final query since I want to display in table both results.
Union() requires to have fulfilled exactly the same properties in both queries so I had to assign "Empty" Department object in second query, but I need to have my Department Name empty and it throws me null exception and I have no idea why it should even throw it, it doesnt make sense to me.
When I tried to assign for example organization.Name into Department.Name suddently it didnt throw me null exception at all.
Is there any possibility to assign empty string into Department name?
var query1 = UserAccountOwnSuppliers
.Where(organization => organization.IsBuyer)
.SelectMany(organization => organization.Departments
.Select(department =>
new UserAccountMarketsForSupplierDTO
{
Organization = new OrganizationBaseDTO
{
Id = organization.Id,
Name = organization.Name,
RegionId = organization.RegionId,
CreatorDepartmentId = organization.CreatorDepartmentId,
CreatorOrganizationId = organization.CreatorOrganizationId,
CreatorId = organization.CreatorId,
},
Department = new DepartmentBaseDTO
{
Id = department.Id,
Name = department.Name
}
})).OrderBy(dto => dto.Organization.Name);
var query2 = UserAccountOwnSuppliers
.Where(organization => organization.IsBuyer)
.Select(organization => new UserAccountMarketsForSupplierDTO
{
Organization = new OrganizationBaseDTO
{
Id = organization.Id,
Name = organization.Name,
RegionId = organization.RegionId,
CreatorDepartmentId = organization.CreatorDepartmentId,
CreatorOrganizationId = organization.CreatorOrganizationId,
CreatorId = organization.CreatorId,
},
Department = new DepartmentBaseDTO
{
Id = 0,
//here it throws null exception when I try to assign some value
Name = "---"
}
}).OrderBy(dto => dto.Organization.Name); ;
var query = query2.Union(query1);
return query.OrderBy(dto => dto.Organization.Name);
DTOs
public class DepartmentBaseDTO : IEntity<int>
{
public string Name { get; set; }
public int Id { get; set; }
}
public class OrganizationBaseDTO : IEntity<int>
{
public string Name { get; set; }
public int? ParentOrganizationId { get; set; }
public int? RegionId { get; set; }
public int CreatorId { get; set; }
public int CreatorOrganizationId { get; set; }
public int CreatorDepartmentId { get; set; }
public string Code { get; set; }
}
public class UserAccountMarketsForSupplierDTO : IEntity<int>
{
public OrganizationBaseDTO Organization { get; set; } = new OrganizationBaseDTO();
public DepartmentBaseDTO Department { get; set; } = new DepartmentBaseDTO();
}
StackTrace
https://pastebin.com/j81yBYYU

Match names in list with elements in class

I wonder if there's any way to match the names in a list with the elements in a class:
I have a class:
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
and a List: List<exampleClass> EnfSist
So that's the way the list is made. Now I would like to know how to match or identify the string inside "name" from my list. To match this class:
tbl_sistematicas b = new tbl_sistematicas
{
ap_enf_id_enfermedad = Convert.ToInt32(EnfSist[0].value),
ap_pac_inicio = Convert.ToInt32(EnfSist[1].value),
ap_pac_inicio_periodo = Convert.ToInt32(2].value),
ap_pac_duracion = Convert.ToInt32(EnfSist[3].value),
ap_pac_duracion_periodo = Convert.ToInt32(EnfSist[4].value),
ap_pac_tratamiento = EnfSist[5].value
};
Once being able to match the same names I won't have to specify each index of every element in the list. The elements in the list have the same name as in the table. Not all elements of the class are being used.
I have something like this: tbl_sistematicas bh = EnfSist.FindAll(x => x.name == bh.?????? );
If I understand the question, you can do this using something like automapper or ValueInjector
An example using ValueInjector
void Main()
{
List<exampleClass> EnfSist = new List<exampleClass>();
EnfSist.Add(new exampleClass { name = "ap_enf_id_enfermedad", value = "12" });
EnfSist.Add(new exampleClass { name = "apap_pac_inicio" , value = "34" });
// etc
tbl_sistematicas b = new tbl_sistematicas();
b.InjectFrom<MyInjection>(EnfSist);
}
public class MyInjection : KnownSourceValueInjection<List<exampleClass>>
{
protected override void Inject(List<exampleClass> source, object target)
{
foreach(var entry in source)
{
var property = target.GetProps().GetByName(entry.name, true);
if (property != null)
property.SetValue(target, Convert.ChangeType(entry.value, property.PropertyType));
}
}
}
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
public class tbl_sistematicas
{
public int ap_enf_id_enfermedad { get; set; }
public int apap_pac_inicio { get; set; }
public int ap_pac_inicio_periodo { get; set; }
public int ap_pac_duracion { get; set; }
public int ap_pac_duracion_periodo { get; set; }
public string ap_pac_tratamiento { get; set; }
}
Note, this will throw an exception if the value can not be converted to an int

Categories