let's say we have something like this
public class Person
{
public string Name {get; set;}
public Country Country {get; set;}
}
public class PersonViewModel
{
public Person Person {get; set;}
public SelectList Countries {get; set;}
}
can automapper be used to perform to parse from Person into PersonViewModel and back ?
Don't use AutoMapper for this - it's not worth it. For example, in the cases where you have a validation failure and you show the form again - AutoMapper is not executed here (usually). We usually go two routes:
If the list is not context-specific, create an HtmlHelper that queries some ISelectListProvider for the select list items: Html.DropDownList(). You'd use your IoC container of choice to locate the personListProvider, query for the list of items, and populate the dropdown list.
If the list is context-specific, just construct the list in the controller action
It sounds like you want to send a Person to the view via the PersonViewModel which has all the bonus info you need to generate and return a new (or updated) Person object.
If this is correct, I don't think you need automapper at all. From what I understand of automapper it is for mapping collection of related objects to a more view model type of state, but in this case, you are sending a Person to the client and trying to receive a Person back. In this case, it seems easier to use your view model to populate the page, but have the page return a Person instead (or extract the updated Person from the view model to save a few keystrokes).
EDIT: That being said, yes you should be able to use automapper to move the info around. Its just a unnecessary layer for this easy scenario.
if one chose to, you could do this:
public class Person
{
public string Name {get; set;}
public Country Country {get; set;}
public Country[] GetCountries
{
... add method for countries here
}
}
Then in your ViewModel you can have your select list pull data from that collection.
public class PersonViewModel
{
public Person Person {get; set;}
public Country[] Countries {get; set;}
public SelectList Countries { get{ .. add new select list code here getting vals from Countries..}}
}
Again, this is for context sensitive lists. You are however muddling concerns a wee bit here (should a person get a list of countries?)
Related
I have a parent and child domain object being mapped to a single ViewModel object. E.G.
class Parent
{
public int ID {get;set;}
public string Name {get;set;}
public Child Child {get;set;}
}
class Child
{
public int ID {get; set;}
public string Name {get; set;}
}
class ParentChildVM
{
public int ID {get;set;}
public string Name {get;set;}
public int ChildID {get;set;}
public string ChildName {get; set;}
}
The types are mapped in static configuration file and it just uses the built in naming conventions to map the properties and achieve the flattening.
I'm using this ParentChildVM with an ASP.NET MVC view that puts ID and Name in form inputs, but only displays ChildID and ChildName. Since the Child's properties are not in form fields, they are not posted back to the server upon saving and are empty in the ParentChildVM that is reconstructed from the posted values.
So I want to remap the Child domain object to my ParentChildVM to fill in the missing properties. But I don't want to map the Parent again because it would overwrite the edited values. Is there any way to map a given Child instance into my existing ParentChildVM with AutoMapper (v6.1.1.0)?
EDIT:
I guess I know I could add a mapping from Child -> ParentChildVM and then use .ForMember to tell it how to map ChildID and ChildName, but in reality there are a lot more properties so what I'm asking is: is there a way to do it and still take advantage of the naming-convention-based mapping? I.E. keep using the "Auto" part of AutoMapper.
First time posted long time reader. I've done a lot of searching and haven't been able to find anything so please excuse me if I missed a past post or something.
In any case I used to be a .net dev and now getting back into .net core MVC. New to MVC and really liking it!
In any case my question is this... is it possible to use a view model to consolidate data? Basically I am writing a timeline from multiple sources taking only the date stamp and description from each. I am hoping to consolidate all into a timeline viewmodel, but not sure if this is appropriate.
EX:
public class order {
public guid id {get; set;}
public datetime orderDate {get; set;}
public string orderDetail {get; set;}
public int orderQuantity {get; set;}
...
}
public class goodsReceipts {
public guid id {get; set;}
public datetime receiptDate {get; set;}
public int receiptQuantity {get; set}
public order order {get; set;}
...
}
public class otherTransactionaldata {
... there are many different transactions such as goodsreceipt
}
then my view model something like this
public class transactions {
public date transactionDate {get; set;}
public string transactionDetail {get; set;}
}
So I basically want to load all transactional data such as (orders, receipts, returns...) into the view model to create a sorted timeline. Am I going down the wrong path here?
Again sorry for the dumb question. I've been reading like crazy and I'm sure I've missed something so I apologize in advance.
Thank you,
E
I have an application where we have elaborate authorization process. However in a method that returns IQueryable, we do not have control on which entities in child collection will be returned.
Here is an example:
public class Parent{
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<Child> Children {get; set;}
}
public class Child {
.... details of child class
}
public MyContext : DbContext{
public DbSet<Parent> Parents;
public DbSet<Child> Children;
}
Now we have different level permissions on the parent and child items and the user with read permission on parent may not have same permission on all child items in the parent. However I have an OData Web API controller written on top of this model which has a Get method on the Parent class with IQueryable as return type and EnableQuery attribute.
public class ParentController : ODataController{
private readonly MyContext _db = new MyContext();
[EnableQuery]
public IQueryable<Parent> Get{
return _db.Parents;
}
.... other methods
}
I have no control on what query the end user will send and if user asks for children, the DBSet will return all the children irrespective of the access permission.
Is there any way I can filter the Children property of the Parent class?
The end user can only use a $expand query to get all children. Therefore he can only query again associated entities. However sometimes you need to filter more data. Then you have to options:
(The complex one) Create a View or Stored Procedure with tvf. See this answer for more details.
(The easy one) Use a dynamic filter for soft delete flags. You can use this if you just want to filter data that has a flag like IsDeleted. Than you can include this extension and enable it like this:
modelBuilder.Filter("IsDeleted", (ISoftDelete d) => d.IsDeleted, false);
This will only show the datasets that do not have the IsDeleted flag set to true.
Here is the situation I am struggling with.
I have an Object Model:
public class MyModel
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
//etc
}
Then I have Object ModelView
public class MyModelView
{
public MyModel MyModelObject;
public SelectList PropToBeSelected1 {get; set;}
public SelectList PropTobeSelected2 {get; set;}
//etc
}
I have the MyModelRepository class as well that does the delete, update operations for MyModel.
All good and clear so far.
Question:
PropToBeSelected1 and PropTobeSelected2 are drop down lists whose contents come from the database. Should the methods retrieving these contents be put in my MyModelRepository? Or should I create another repository for ViewModel?
Thank you.
First you really don't want domian-ish objects in your viewModel. Your viewModel should be clean with only primitives (like strings, ints... etc). So I'd suggest using a AutoMapper to map your two string props to your viewModel.
With the select list, there are many ways to go about this but I can imagine if they are lists of properties then they are not actual entities, but value objects instead. In this case creating a repository for them is over kill and boarders bad design.
I'd put the 'get' of the property lists in your MyModelRepository. Something like
_myModelRepository.getProperties1For(myModel);
Then AutoMap again on to get your select list.
Edit:
Like #M.Radwan pointed out for complex domain models I'll make viewModels insdie viewModels for easy of mapping.
Domain Model--
public class User : Entity
{
public Address Address { get; set; }
}
public class Address
{
public string Street { get; set; }
public string Zip { get; set; }
}
would map to
public class DetailsViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public AddressViewModel Address { get; set; }
public class AddressViewModel
{
public string Street { get; set; }
public string Zip { get; set; }
}
}
which in our experience has been the only reason to add any complexity to your viewModel. We will put SelectLists in our viewModel though but lately we've been using IEnumerables of inner viewModels and calling custom EditorFor or DisplayFor to turn them into a dropdown / list of checkboxes / radio buttons.
The answer is NO, you should not make any repository for them if you really need them with this view. so they probably are value objects as #jasonhooten said and they should connected to the main aggregate object that used by the repository
Finally I don't decide the ViewModel structure until I finish the view and make it working first and this why I founder and create DevMagicFake, by using DevMagicFake you will delay all decisions of the design regarding the structure of the ViewModel or the repository or how you will use service layer, all this will be delayed after full complete your view and make it working first as BDD (Behavior Driven Development) and TDD (Test Driven Development) so you can take the right decisions of the design and the object model itself
So I just create the action method as the following
public ActionResult List(MyModelView myModelView)
{
FakeRepository<MyModelView> repository = new FakeRepository<MyModelView>();
repository.Add(myModelView);
}
This fake repository will enable me to save and retrieve my whole model even it's a complex model until I finish and complete the whole view and make it working first, and then I start thanking on how the real design and the real repository should looks like, and do on
For more information about DevMagicFake and this approach see this link
DevMagicFake on CodePlex
I have the following domain class:
public class Product
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Product> RelatedProducts { get; set; }
}
I have the following DTO class:
public class ProductDTO
{
public ProductDTO(Product product)
{
Id = product.Id;
Name = product.Name;
}
public Guid Id { get; private set; }
public string Name { get; private set; }
}
I have the following method in my service:
public ProductDTO GetBySlug(string slug)
{
Product product = productRepository.GetBySlug(slug);
return (product != null) ? new ProductDTO(product) : null;
}
I have the following action in my controller:
public ActionResult Details(string slug)
{
ProductDTO viewModel = productService.GetBySlug(slug);
return View("Details", viewModel);
}
After reading around a bit is my understanding that using a DTO as a viewmodel is ok as the current scenario is simple and straight forward. My confusion occurs when the data that I want to return gets a bit more complex. Let's assume that I also want to return the list of related products to the view as well. Where would I add this list?
I read that a DTO is a flattened version of your domain entity that is used to transfer data. Does that mean that a generic list containing the related products should not be allowed inside the DTO? The answer I received so far suggests so. How do I then get the related products to the controller?
One option is:
Instead of returning the ProductDTO in the service I would create a new class that holds ProductDTO and the List of type ProductDTO for the related products and return it from the service. In the controller I would then either pass the new class to the view or create a separate ProductViewModel that holds ProductDTO and the List of type ProductDTO for the related products, populate it and pass that to the view.
Is this a good or a bad idea? Why?
Thanks
I wouldn't place the list inside the DTO at all, because it does not naturally belong there. And I am also not sure what you mean with 'wrapper class'. All you need is a list of products, and it is perfectly OK to have another method on the service which returns this list.
Consequently, you would have something like this in your service:
public IList<ProductDTO> GetRelatedProducts(ProductDTO productDTO)
{
...
The most important idea behind a viewmodel (the thing that is called service above) is that it mediates between the UI and the business model. In other words: It orchestrates and aggregates the business model in a way that is relevant to the UI. And if the UI wants a list of related products at some point, then the service has to deliver it. It's really as simple as this, and it is completely irrelevant here whether the business model itself also has this concept.
HTH!
Thomas
P.S.
If your DTOs get larger and your lists longer, you might consider to introduce another (simplified) DTO with only the name and some sort of identifier to reduce the amount of unnecessary data you have to retrieve from the repository.