Ok dead basic question, I'm a self taught developer so often I seem to have gaps where I can't decide which was is the right way... and this is one of them!! Simple I have a view model which has a collection of child items. But where these classes are defined I can't decide if the child object should be a subclass of the parent...
For example this:
public class ActionChartViewModel
{
public IEnumerable<ActionChartItemViewModel> Items { get; set; }
public TextPagingInfo TextPagingInfo { get; set; }
}
public class ActionChartItemViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Rating { get; set; }
public string Comment { get; set; }
public string AssignedToUserName { get; set; }
public string ContactRequested { get; set; }
public bool Resolved { get; set; }
public int NoteCount { get; set; }
public string ContactDetails { get; set; }
public int ResponseId { get; set; }
}
Or this:
public class ActionChartViewModel
{
public IEnumerable<Item> Items { get; set; }
public TextPagingInfo TextPagingInfo { get; set; }
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Rating { get; set; }
public string Comment { get; set; }
public string AssignedToUserName { get; set; }
public string ContactRequested { get; set; }
public bool Resolved { get; set; }
public int NoteCount { get; set; }
public string ContactDetails { get; set; }
public int ResponseId { get; set; }
}
}
I prefer the second one for a code readability and simplicity front, but I don't know the pros and cons of subclasses. What would you guys think??
Thanks in advance!!
I would use separate classes (in same file) as opposed to an inner class. Inner class would be useful when it serves only the parent class, i.e. would not be accessed from outside of the parent class, only by the parent class methods, etc. In your case the inner class needs to be used on view(s), so I don't see a need for it. The first option, i.e. separate classes, is actually simpler to me and reads better.
"SubClass" is when you create more concrete implementations (inherits) of its types. As # bloparod says, you're doing "inner classes". I also rarely use inner classes. Sometimes I use some private or internal classe as a temporary. If you do that, you will need to create with the sintaxe like:
ActionChartViewModel.Item item = new ActionChartViewModel.Item();
I usually separete files and use public classes but sometimes when I have lots and lots of ViewModel, I think a good pratice is to keep all of the same category of ViewModels on a single file and inherited when necessary, for sample:
File: ProductViewModel.cs
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string CategoryName { get; set; }
}
public class ProductDetailViewModel : ProductViewModel
{
public int Stocke { get; set; }
public string Obs { get; set; }
public IEnumerable<ProductMovViewModel> Inventory
/* other properties */
}
public class ProductMovViewModel
{
public int Id { get; set; }
public DateTime Date { get; set;
public int Amout { get; set; }
}
As a good pratice too you can separete in files your ViewModels, as you prefer.
Related
<I have two classes with too many fields . which are basically the Model of MVC . I want to create a third class which take few fields from both 1st,2nd by inheritance but not all the fields of 1st and 2nd class is it possible by inheritance .I want to
make a new class without declare field in it
public class OpeningBalanceLiteModel
{
public Int64 LedgerId { get; set; }
public String LedgerCode { get; set; }
public Int64? ParentLedgerId { get; set; }
public Decimal OpeningBalance { get; set; }
public Boolean? Status { get; set; }
public Int32? LedgerCategoryId { get; set; }
public Byte Is_Active { get; set; }
public Byte Is_Deleted { get; set; }
}
public class DrCrDetailLiteModel
{
public Int32 Id { get; set; }
public Int32 TransactionTypeId { get; set; }
public Int32? AmountType { get; set; }
public Decimal? Amount { get; set; }
public String VoucherNarration { get; set; }
public Int32 FinancialYearId { get; set; }
public Int64 CompanyId { get; set; }
public Decimal? SubsidiaryId { get; set; }
public Decimal? LocationBranchId { get; set; }
public Decimal? DivisionId { get; set; }
public Int32? DepartmentId { get; set; }
public Int32? ProjectId { get; set; }
public Int32? ProjectEstimationId { get; set; }
public Boolean? IsAdvancePayment { get; set; }
public Boolean? IsHiddenFromSourceLedger { get; set; }
public Boolean? IsReversed { get; set; }
}
public class OpeningBalanceDrCrMurg
{
}```
* i wan to add 3 fields of both class by inheritance
We commonly calls inheritance a "is a" relation ship, an apple is a fruit. If you do not include all properties it is not a "is a" relationship. Is all fruits have a color, then an apple must have a color.
Moreover, c# does not support multiple inheritance. You could inherit from multiple interfaces, and that would also allow you to use explicit interface implementation to hide properties unless a reference of the interface type is used. But I get the impression that your goal is implementation inheritance.
My recommendation would be to use Composition instead of inheritance. Group your properties in to logical groups, and compose these models, for example:
public class LedgerModel{
public Int64 LedgerId { get; set; }
public String LedgerCode { get; set; }
public Int64? ParentLedgerId { get; set; }
}
public class OpeningBalanceLiteModel{
LedgerModel {get;set;}
...
}
That should allow finer grained control to allow you to include any combination of property-groups in your classes.
you should create a Base Class ex:
public class BaseClass
{
public int Id1 { get; set; }
public int Id2 { get; set; }
public int Id3 { get; set; }
}
public class childrenClass1 :BaseClass
{
...
}
public class childrenClass2:BaseClass
{
...
}
Now children class1 and 2 have Id1/Id2/Id3
I'm not yet dependent to either Mapster or AutoMapper. For now I'm using handwritten mappings because I couldn't find a mapper who could do this with smaller code.
The problem is how do we map flatten structures to complex objects? I think a lot of people could benefit from a good mapping example for such a complex object. I've got even a mapping condition based on CopyOfficeAddressAsInvoiceAddress whether or not the office address needs to be copied as invoice address. I've looked all over the place but couldn't get it to work.
Maybe I should also use a different naming to make it more clear for the mapping algorithm?!
The biggest question could such a map being resolved by a mapper or is this to complex? Al the demo's I've seen were using dto and model objects that are quite similar to each other. I didn't get the point of mapping an object to another object that 99% similar to each other.
I have a Command (I'm using Mediatr) that looks like as follows:
public class Command : IRequest<IActionResult>
{
public string AccountName { get; set; }
public string ContactFirstName { get; set; }
public string ContactLastName { get; set; }
public string ContactEMail { get; set; }
public string ContactPhoneNumber { get; set; }
public string BankAccount { get; set; }
public string Bank { get; set; }
public string OfficeName { get; set; }
public string OfficeAddressStreet { get; set; }
public int OfficeAddressStreetNumber { get; set; }
public string? OfficeAddressStreetNumberAddition { get; set; }
public string OfficeAddressPostalcode { get; set; }
public string OfficeAddressCity { get; set; }
public string OfficeAddressCountry { get; set; }
public string? OfficeInvoiceAddressStreet { get; set; } = null;
public int? OfficeInvoiceAddressStreetNumber { get; set; } = null;
public string? OfficeInvoiceAddressStreetNumberAddition { get; set; } = null;
public string? OfficeInvoiceAddressPostalcode { get; set; } = null;
public string? OfficeInvoiceAddressCity { get; set; } = null;
public string? OfficeInvoiceAddressCountry { get; set; } = null;
//[Ignore]
public bool? CopyOfficeAddressAsInvoiceAddress { get; set; } = false;
public string? AssociationIdentifier { get; set; } = null;
}
And I want it to be mapped to the following models:
public class Account
{
public int Id { get; set; }
public string AccountName { get; set; }
public IList<Contact> Users { get; set; }
public IList<Office> Offices { get; set; }
public string Bank { get; set; }
public string BankAccount { get; set; }
public string? AssociationIdentifier { get; set; }
}
public class Office
{
public int Id { get; set; }
public string Name { get; set; }
public Address ContactAddress { get; set; }
public Address InvoiceAddress { get; set; }
public bool HeadQuarter { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string Postalcode { get; set; }
public int StreetNumber { get; set; }
public string StreetNumberAddition { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EMail { get; set; }
public string PhoneNumber { get; set; }
}
First of all, my experience is mainly using Automapper, and it is definitely possible to map complex types like this.
But your command does not need to be completely flat. There is nothing inherently wrong with DTOs being similar to your domain models. Using Automapper this is fairly easy as properties with the same name are mapped 1:1.
It could be that you are submitting a form with all the properties flattened in one object. In that case you could define either a seperate map for this object and each domain object.
CreateMap<AccountDto, Account>(); // mapping logic omitted
CreateMap<AccountDto, Office>();
...
Or you could map the one object to a range of objects using Tuples.
CreateMap<AccountDto, (Account, Office, ...)>(); // mapping logic omitted
But if you define seperate DTOs and make mapping profiles for them, it will probably ease your whole mapping experience. For copying the address, you can simply do something like this, in that case.
if (copyAddress)
{
office.InvoiceAddress = _mapper.Map<Address>(addressDto);
}
Say I have the following model:
class Product
{
public string Id { get; set; }
public string Name { get; set; }
public string Brand { get; set; }
public string Description { get; set; }
public string Image { get; set; }
}
For a list view in the client I would only need the following:
class ProductListView
{
public string Name { get; set; }
public string Image { get; set; }
}
For a detail view I would need the following:
class ProductDetailView
{
public string Name { get; set; }
public string Brand { get; set; }
public string Description { get; set; }
public string Image { get; set; }
}
For an update of the name, I would need:
class ProductUpdateName
{
public string Id { get; set; }
public string Name { get; set; }
}
For an update of the description and brand, I would need:
class ProductUpdateDescriptionAndBrand
{
public string Id { get; set; }
public string Brand { get; set; }
public string Description { get; set; }
}
For all these different combinations, do I create the same number of classes? This sounds horrible though.
I can do anonymous classes instead but then I would need reflection to figure out the actual fields. This also sounds wrong.
So what is the best way?
A DTO by nature should represent a particular use case. The class is a representation of the data that will be transferred - hence the name. As such, whenever there's different data, yes, you should have a different DTO.
Now, that doesn't stop you from building upon your DTOs via inheritance. For example, ProductDetailView could inherit from ProductListView, since it is a superset of the properties of ProductListView. However, you should not inherit from ProductUpdateDescriptionAndBrand, because that includes an Id property, which ProductDetailView does not.
In those cases, you can opt to employ composition instead. For example, you could have something like:
public class BrandDescription
{
public string Brand { get; set; }
public string Description { get; set; }
}
And then:
public class ProductUpdateDescriptionAndBrand
{
public string Id { get; set; }
public BrandDescription BrandDescription { get; set; }
}
public class ProductDetailView : ProductListView
{
public BrandDescription BrandDescription { get; set; }
}
Otherwise, then just keep the classes as they are and use all of them as appropriate. Remember also that each of these serves a particular purpose (representing a particular group of data being transferred). As such, a property like Description, doesn't necessarily mean the same thing in all places. Just because the properties are similar or named the same doesn't mean they are handling the same concept(s).
I have to import a set of data from one database to another with a somewhat different schema, and I'm considering using AutoMap. I could just write a bunch of SQL scripts, but I already have both databases in EF and I want to learn AutoMap ...
While many of the classes are similar, the problem I'm having is where the structure is really different. The target models were designed with several more layers of classes. Instead of flattening, I need to expand.
The target classes have the following properties:
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
public ContactInfo Location { get; set; }
public List<Policy> Policies { get; set; }
}
public class ContactInfo
{
public int Id { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public State State { get; set; }
public string Zip { get; set; }
public string EMail { get; set; }
public List<Phone> PhoneNumbers { get; set; }
}
public class Phone
{
public int Id { get; set; }
public string Name { get; set; }
public string Number { get; set; }
}
public class Policy
{
public int Id { get; set; }
public PolicyNumber PolicyNumber { get; set; }
public List<Transaction> Transactions { get; set; }
}
The source tables, however, are relatively flattened.
public partial class Account
{
public string AccountId { get; set; }
public string AccountName { get; set; }
public string PolicyNumber { get; set; }
}
public partial class Transaction
{
public int TransactionId { get; set; }
public int AccountId { get; set; }
public Nullable<System.DateTime> EffectiveDate { get; set; }
public string InsuredName { get; set; }
public string InsuredAddress { get; set; }
public string InsuredCity { get; set; }
public string InsuredState { get; set; }
public string InsuredZip { get; set; }
public string InsuredPhone { get; set; }
}
I can create the Map, but I don't know how to tell AutoMapper to handle converting the string Policy to a policy object and then add it to the list of Policies.
Mapper.CreateMap<Source.Account, Destination.Account>();
Even worse, the source data inexplicitly has the name and address info at the transaction level. Before you tell me that AutoMap might not be the best solution, please understand that these two source tables are 2 out of over 40 tables in this database, and that the others are not nearly as troublesome.
Can I configure AutoMap to convert the string property PolicyNumber to a Policy Object and add it to the Policies List of the target class?
Any suggestions on how I can get the name and address information from the Transaction into a ContactInfo class and add it at the Account level?
Thank you.
Thanks to Thomas Weller. Custom Value Resolvers handled exactly what I needed.
You can see my previous question which related with many to many relation but with auto generated mapping table.
I have 2 model, HrTraining and HrPerson. Any people can be assigned to one or more Trainings. You can see my model as below
public class HrTraining
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrMapTrainingPerson> HrMapTrainingPerson { get; set; }
}
public class HrMapTrainingPerson
{
public int Id { get; set; }
public string Status { get; set; }
public int HrTrainingId { get; set; }
public int HrPersonId { get; set; }
public virtual HrTraining HrTraining { get; set; }
public virtual HrPerson HrPerson { get; set; }
}
public class HrPerson
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrMapTrainingPerson> HrMapTrainingPerson { get; set; }
}
How can i take all training objects which assingned to a person with efficient way.
So you want to find a person, and get all the trainings assigned to it? There are lot of ways.. but using your models, this could be something like this
var trPersons = dbContext.HrPerson.Find(idPerson).HrMapTrainingPerson.ToList();
foreach(var trPerson in trPersons) {
var training = trPerson.HrTraining;
//do what you want, here you can get trPerson.HrTraining.Name for instance
}