I have these two classes
enum CustomerType {
CitizenBank = 0,
Wellsfargo = 1
}
public abstarct class CustomerDto {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
public CitizenBank: CustomerDto {}
public Wellsfargo: CustomerDto {}
Public Class CustomerEntity {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
I wrote a class to convert from entity to DTO
public class EntityModelToModel {
///Method to convert
public CustomerDto ToDto(CustomerEntity customerEntity) {
/// returns type customerDto based on customertypeid
switch (CustomerType) {
case Wellsfargo
return New Wellsfargo()
case citizen
return new citizen() //calls method that converts from customer Entity to citizen
}
}
I have method to check if my types match
public bool CanExecute(CustomerEntity customerEntity) {
foreach(var customerType in Enum.GetValues(typeof(Enums.customerType) if (customerEntity.CustomerType == customerType)
return true
else
false
}
}
Now my calling code I have array of CustomerEntity[] which have two items of customerid for wellsfargo and citizens. I want to do this
var res = CustomerEntity[].where(x => EntityModelToModel.CanExecute(x).Select(x => EntityModelToModel.ToDto(x))
My problem is:
If my array has two items this only checks the first items and returns.
What I want is it should check for two items and return them.
I think that you should change your CanExecute method like this:
public static class EntityModelToModel
{
// ...
public static bool CanExecute(CustomerEntity customerEntity)
{
foreach (var customerType in Enum.GetValues(typeof(CustomerType)))
{
if (customerEntity.CustomerTypeId == (int)customerType)
{
return true;
}
}
return false;
}
}
Because your method break execution flow after first check.
Related
I want to practice code with DRY principle, but my method uses 2 different classes, classOneDTO and classTwoDTO.. They have different properties and I want to linked it with PRIMARYIDENTIFIER prop with both have the same..
How can I create a generic method to get the property that I want to query with Linq.
Updated: my purpose is to have a generic method that will query the PrimaryIdentifier and get the data to it whether they are using classOneDTO or classTwoDTO. Is there a way to have a single generic method to do this?
private void genericMethod<T>(List<T> workList, GridView grid, int columnNo)
{
if (workList.Any())
{
string CodeString = default;
// Want to dynamic get the properties in different class with PrimaryIDentifier property
// want to check if PrimaryIdentifier is NULL OR EMPTY
var getDataOne = workList.Cast<classOneDTO>().FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
// causing error because of the CAST if wrong type request
var getDataTwo = workList.Cast<classTwoDTO>().FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getDataOne != null || getDataTwo != null)
{
CodeString = (getDataOne != null) ? getDataOne.PrimaryIdentifier : getDataTwo.PrimaryIdentifier;
}
}
}
public class classOneDTO
{
public int PatientID { get; set; }
public string PrimaryIdentifier { get; set; }
public string FirstName{ get; set; }
// so oonnn...
}
public class classTwoDTO
{
public int EntryID { get; set; }
public string PrimaryIdentifier { get; set; }
public string Location{ get; set; }
// so oonnn...
}
All that you need is to make both your classes implement the same interface, i.e. IDTO:
public interface IDTO
{
string PrimaryIdentifier { get; set; }
}
Then you can tell the compiler to accept only types that implement your new interface:
private void GenericMethod<DTO>(List<DTO> workList, GridView grid, int columnNo)
where DTO: IDTO
{
if (workList.Any())
{
string CodeString = default;
var getData = workList.FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getData != null)
{
CodeString = getData?.PrimaryIdentifier;
}
}
}
(Pay attention to the 2nd row)
Additionally, I also made minor adjustments to your class and method namings based on standard .Net naming convention.
Here's the full code:
public class Client
{
private void GenericMethod<DTO>(List<DTO> workList, GridView grid, int columnNo)
where DTO: IDTO
{
if (workList.Any())
{
string CodeString = default;
var getData = workList.FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getData != null)
{
CodeString = getData?.PrimaryIdentifier;
}
}
}
}
public class ClassOneDTO : IDTO
{
public int PatientID { get; set; }
public string PrimaryIdentifier { get; set; }
public string FirstName { get; set; }
// so oonnn...
}
public class ClassTwoDTO : IDTO
{
public int EntryID { get; set; }
public string PrimaryIdentifier { get; set; }
public string Location { get; set; }
// so oonnn...
}
public interface IDTO
{
string PrimaryIdentifier { get; set; }
}
EDIT: as Johnathan Barclay correctly pointed out, there's actually no need to have a generic method if you don't need some more advanced logic there that you didn't show in your example.
private void GenericMethod(IEnumerable<IDTO> workList, GridView grid, int columnNo)
{
if (workList.Any())
{
string CodeString = default;
var getData = workList.FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getData != null)
{
CodeString = getData?.PrimaryIdentifier;
}
}
}
This is how database structure looks like:
Vehicle has lot of CanNetworks and each CanNetwork has lot of ECUs. And that would save perfectly if that was only I have.
But, each vehicle also has one special ECU called gatewayECU so problem happens with saving because entity framework core does not know how to handle that scenario. It needs to insert vehicle before inserting ecus, but how to insert vehicle when ecu is not inserted.
This is what I tried: ignore (delete, invalidate) gatewayecu field (column is nullable in database), then I insert whole graph and then update vehicle with gatewayEcuId field I stored in some variable before doing anything.
Solution is not pretty. How to handle this scenario.
public class Vehicle : BaseEntity
{
public Vehicle()
{
CANNetworks = new List<CANNetwork>();
}
public List<CANNetwork>? CANNetworks { get; set; }
public ECU? GatewayECU { get; set; } = default!;
public int? GatewayECUId { get; set; }
}
public class CANNetwork : BaseEntity
{
public CANNetwork()
{
ECUs = new List<ECU>();
}
public string Name { get; set; } = default!;
public ICollection<ECU>? ECUs { get; set; }
public int VehicleId { get; set; }
public Vehicle? Vehicle { get; set; } = default!;
}
public class ECU : BaseEntity
{
public int CANNetworkId { get; set; }
public CANNetwork? CANNetwork { get; set; } = default!;
}
This is ugly solution which I don't want:
public async Task<int> Insert(Vehicle vehicleDefinition, ECU vehicleGatewayECU)
{
var result = -1;
using (var transaction = _databaseContext.Database.BeginTransaction())
{
result = await Insert(vehicleDefinition);
if (vehicleGatewayECU != null)
{
var ecu = await _databaseContext.ECUs.FirstOrDefaultAsync(x => x.Name == vehicleGatewayECU.Name && vehicleDefinition.Name == x.CANNetwork.Vehicle.Name);
if (ecu != null)
{
vehicleDefinition.GatewayECUId = ecu.Id;
result = await Update(vehicleDefinition);
transaction.Commit();
return result;
}
}
else
{
transaction.Commit();
}
}
return result;
}
EDIT:
I am now thinking about changing table structure in a way to get rid of gatewayECU field on Vehicle, and put some flag IsGatewayEcu in ECU table
I have a list of custom class called List<Notifications>.
The class is below:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
}
Before adding an instance of the Notification class to my custom list, I want to check if it is already in the list.
What is the best way to achieve this?
You can use 1.) Contains, but then you have to override Equals (+ GethashCode).
bool contains = list.Contains(someNotificationInstance);
For example:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
public override bool Equals(object obj)
{
return obj is Notification && string.Equals(ID, ((Notification)obj).ID);
}
public override int GetHashCode()
{
return ID == null ? 0 : ID.GetHashCode();
}
}
2.) another option is to provide a custom IEqualityComparer<Notification> for Contains:
public class NotificationComparer : IEqualityComparer<Notification>
{
public bool Equals(Notification x, Notification y)
{
return x.ID == y.ID;
}
public int GetHashCode(Notification obj)
{
return obj.ID == null ? 0 : obj.ID.GetHashCode();
}
}
On this way you don't need to modify the original class. You can use it in this way:
bool contains = list.Contains(someInstance, new NotificationComparer());
3.) Probably the easiest approach is using Enumerable.Any:
bool contains = list.Any(n => someInstance.ID == n.ID);
4.) The most efficient approach is using a set if no duplicates are allowed in the collection anyway. Then you can use the first or second approaches for a HashSet<T>:
var set = new HashSet<Notification>(new NotificationComparer());
set.Add(instance1);
bool contains = !set.Add(instance2);
You can check it with Contains method.
if (!mylist.Select(l => l.ID).Contains(mynewid)) {
var item = new Notifcation();
item.ID = mynewid;
item..... // fill the rest
mylist.Add(item);
}
Maybe a better approch would be use of Dictionary.
IListModel exposes a generic list property called Items of abstract type ListItemModel. But when I try to convert any derived class to IListModel I get "Object reference not set to an instance of an object" error.
public abstract class ListItemModel
{
public string UserName { get; set; }
public string SomeProperty { get; set; }
}
public interface IListModel<T> where T : ListItemModel
{
List<T> Items { get; set; }
}
public class UserListModel : IListModel<UserListItemModel>
{
public string Query { get; set; }
public int TotalUsers { get; set; }
public List<UserListItemModel> Items { get; set; }
}
public class UserListItemModel : ListItemModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
var users = new UserListModel
{
Query = "a",
TotalUsers = 1111,
Items = new List<UserListItemModel>
{
new UserListItemModel {FirstName = "a", LastName = "b"}
}
};
// later in the application users will be passed around as an object which
// must cast it to IListModel<ListItemModel> in order to access its properties
// but converted will return null
var converted = users as IListModel<ListItemModel>;
foreach (var item in converted .Items)
{
item.SomeProperty = DoSomethingHere(item.UserName);
}
What I am trying to achieve here is being able to populate SomePropery from ListItemModel base class.
Please refer to: as (C# reference)
However, if the conversion isn't possible, as returns null instead of raising an exception.
Basically, what's happening is that you're doing an invalid cast, and the result of that invalid cast depends on the form of casting used.
var converted = users as IListModel<ListItemModel>; // converted is null
var converted = (IListModel<ListItemModel>)users; // raises exception
Is casting actually necessary? UserListModel : IListModel<UserListItemModel> seems to indicate that it IS an IListModel of the type you want, so you should just be able to supply it into the foreach block and work from that, no?
Create a generic list item reference interface:
public interface IListItemModel
{
List<ListItemModel> Items { get; }
}
Have your classes implement with an explicit constructor:
List<LIstItemModel> IListModel.Items
{
get { return this.Items; }
}
And then you can cast users to IListModel.
Thanks to "Brian Mains" and "Kyle Baran" my problem is solved. Here is the working code:
public abstract class ListItemModel
{
public string UserName { get; set; }
}
public interface IListModel
{
List<ListItemModel> ListItems { get; }
}
public abstract class BaseListModel<T> : IListModel where T : ListItemModel
{
public List<T> Items { get; set; }
public List<ListItemModel> ListItems
{
get { return Items.Cast<ListItemModel>().ToList(); }
}
}
public class UserListModel : BaseListModel<UserListItemModel>
{
public string Query { get; set; }
public int TotalUsers { get; set; }
}
public class UserListItemModel : ListItemModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
var users = new UserListModel
{
Query = "a",
TotalUsers = 1111,
Items = new List<UserListItemModel>
{
new UserListItemModel {FirstName = "a", LastName = "b"}
}
};
// and finally I can cast the collection to IListModel
var converted = users as IListModel;
foreach (var item in converted .Items)
{
item.SomeProperty = DoSomethingHere(item.UserName);
}
I have two models:
public class CarRent
{
public string CarName { get; set; }
public string SystemId { get; set; }
public DateTime RentEndDate { get; set; }
}
public class CarPurchase
{
public string CarName { get; set; }
public string SystemId { get; set; }
public decimal Mileage { get; set; }
}
I need to combine them into one list, group by CarName and then inside each group I need to sort models initially by SystemId, but then if models have the same SystemId - I need to sort CarRent models by RentEndDate and CarPurchase by Mileage.
What I have tried:
I defined an interface:
public interface ICarPurchaseOrdered
{
string CarName { get; }
string SystemId { get; }
string Order { get; }
}
and got my models to implement it, the Order property just returns string representation of second order criteria, then I defined a view model:
public class GroupedCardList
{
public string CarName { get; set; }
public IEnumerable<ICarPurchaseOrdered> Cars { get; set; }
}
then I have a grouper that just groups my models:
public class CarGrouper
{
IEnumerable<GroupedCardList> Group(IEnumerable<ICarPurchaseOrdered> cars)
{
return cars.GroupBy(c => c.CarName)
.OrderBy(c => c.Key)
.Select(c => new GroupedCardList()
{
CarName = c.Key,
Cars = c.OrderBy(n => n.SystemId)
.ThenBy(n => n.Order)
});
}
}
But it doesn't work right because it sorts strings and I get the car purchase with Milage=1200 before the car with Milage=90.
I know that example is a little bit contrived but it perfectly represents the issue that I have right now. Please give me some advice.
One way to do it would be to implement a custom IComparer. If you extract a common base class:
public class Car
{
public string CarName { get; set; }
public string SystemId { get; set; }
}
public class CarRent : Car
{
public DateTime RentEndDate { get; set; }
}
public class CarPurchase : Car
{
public decimal Mileage { get; set; }
}
Then a IComparer<Car> implementation might look like this:
public class CarComparer : IComparer<Car>
{
public int Compare(Car x, Car y)
{
// compare by system id first
var order = string.Compare(x.SystemId, y.SystemId);
if (order != 0)
return order;
// try to cast both items as CarRent
var xRent = x as CarRent;
var yRent = y as CarRent;
if (xRent != null && yRent != null)
return DateTime.Compare(xRent.RentEndDate, yRent.RentEndDate);
// try to cast both items as CarPurchase
var xPurc = x as CarPurchase;
var yPurc = y as CarPurchase;
if (xPurc != null && yPurc != null)
return decimal.Compare(xPurc.Mileage, yPurc.Mileage);
// now, this is awkward
return 0;
}
}
You can then pass the comparer instance to List.Sort and Enumerable.OrderBy.
You can use int.Parse and order integers instead of strings
c.OrderBy(n => n.SystemId)
.ThenBy(n => int.Parse(n.Order))
The ICarPurchaseOrdered.Order used to order (then) by is a string type; Hence why the ordering is done alphabetically.
I would suggest to change the type of ICarPurchaseOrdered.Order to object,
so the Orderbycan use the underlying object (eitherDateTimeorDecimal`) to order.
**Update:
Try this
c.OrderBy(n => n.SystemId)
.ThenBy(n => n.GetType())
.ThenBy(n => n.Order);