Assuming I wan't to use single class to create and update an object in REST API - how I can do this without code duplication?
Create an object (POST) - all fields should be [Required].
Update an object (PATCH) - I want to use same class but fields should not be required as it can be done partially.
I can use below class for POST but can't for PATCH - as only Name may be updated (provided along the request) - which is OK.
public class Person
{
[Required]
public string Name { get; set; }
[Required]
public string LastName { get; set; }
}
The only solution I see (that causes code duplication) is:
public class CreatePerson
{
[Required]
public string Name { get; set; }
[Required]
public string LastName { get; set; }
}
public class UpdatePerson
{
public string Name { get; set; }
public string LastName { get; set; }
}
Related
I am new to Automap, and I am trying to filter out the result. I want to know how to map nested dtos.
Post Entity:
public class Post
{
public Author? Author { get; set; }
[Required] [Key] public int Id { get; set; }
[Required] public string Title { get; set; }
[Required] public string Description { get; set; }
[Required] public string Body { get; set; }
}
PostRead: (dto)
public class PostRead
{
public DateTime Created { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string Description { get; set; }
// Author would work but I want only the AuthorRead data
public AuthorRead Author;
}
Author Entity
public class Author
{
[Key] [Required] public int Id { get; set; }
[Required] public string Name { get; set; }
public IEnumerable<Post> Posts { get; set; }
}
AuthorRead.cs (dto)
public class AuthorRead
{
public int Id { get; set; }
public string Name { get; set; }
}
Technically if I use Author Entity in PostRead, it works but it'll give the list of the posts the Author has, and i want only the information that is in the AuthorRead (so the API response doesn't send the list of posts of the Author itself).
how I can map the object of type Author to the type AuthorRead in the PostRead?
Errors:
AutoMapper.AutoMapperMappingException : Missing type map configuration or unsupported mapping.
Mapping types:
Object -> PostRead
System.Object -> OhMyBlogAPI.Models.PostRead
at lambda_method22(Closure , Object , PostRead , ResolutionContext )
at OhMyBlogAPI.Tests.AutomapTests.MockPost_MapsTo_PostRead() in
What I tried , and searching a lot.
CreateMap<Post, PostRead>()
.ForMember(m
=> m.Author, o
=> o.MapFrom<Author, AuthorRead>("Author"));
And profiles (each line represent relevant profiles content):
CreateMap<Post, PostRead>();
CreateMap<Author, AuthorRead>();
My bad, the code works.
I misconfigured something in the Unit testing. I am really sorry.
I have a sqlite database which has some tables and columns like the following:
int Id
text Name
text Comment
...
And my object in my project looks like this:
Public Class Entry {
public int Id { get; set; }
public String Name { get; set; }
public String Comment { get; set; }
public String Additional { get; set; }
}
This can happen, because my programm need to handle different versions of the database.
EF Core now trys to access the Additional field of the database but returns an error that it cannot find the field. (Expected behaviour)
Now my question is, if there is a way to ignore this error and return a default value for the property?
I could bypass the error by making the properties nullable. But i don't want to check each property with .HasValue() before accessing it. Because the real database has 50+ columns in the table.
https://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-first.aspx
Put NotMapped as an attribute on the Additional field:
using System.ComponentModel.DataAnnotations.Schema;
Public Class Entry {
public int Id { get; set; }
public String Name { get; set; }
public String Comment { get; set; }
[NotMapped]
public String Additional { get; set; }
}
This tells EF that the field is not a column in the database.
I would advise you to split your domain object from that persisted dto object. That way you can have different dtos with different mappings. Now you can instantiate your domain object with your dto and decide inside your domain object what values are the correct default values.
public class Entry
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public string Additional { get; set; }
}
public class EntryDtoV1
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
}
public class EntryDtoV2
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public string Additional { get; set; }
}
Now you only need to create some kind of factory that creates the correct repository depending on what database version you query.
I would like to access the email of this class into another class that I am already instantiated on my render page.
Any help very much appreciated.
public class Access
{
public string Email { get; set; } //I want this value...
}
public class Types
{
public string Id { get; set; }
public string Sum { get; set; }
public string Addition { get; set; }
public string Email { get; set; } // ...to be this value inside my class TYPES
}
Well I think you can simply use a copy constructor for the Types class with the Access instance as parameter from which you want to copy the email value when creating a new Types instance.
From what you said it seems you don't care if its a particular instance (as your post is a bit confusing between class and instance)
public class Types
{
public string Id { get; set; }
public string Sum { get; set; }
public string Addition { get; set; }
public string Email { get; set; }
public Types(Access access)
{
Email = access.Email
}
}
This should have come up like a million times by now, but I can't seem to find anything solid that I like.
Please, consider
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
}
which appears twice in my view model
public class MyViewModel
{
public Person MainContact { get; set; }
public Person AltContact { get; set; }
}
Main contact is always required. Alternative contact is not required, but if anything is entered it should validate the entry. If I was to have 2 different Contact classes, they would be described like this:
public class MainContact
{
[Required]
[StringLength(50)]
string FirstName { get; set; }
[Required]
[StringLength(50)]
string LastName { get; set; }
string Position { get; set; }
}
public class AltContact
{
[StringLength(50)]
string FirstName { get; set; }
[StringLength(50)]
string LastName { get; set; }
string Position { get; set; }
}
But, I don't want to have 2 different Contact classes with the exactly same properties.
I would like one set of validations applied to one instance of Person class and another set of validations applied to a different instance of the same Person class. The solution also has to work with the client side validation with unobtrusive js turned on.
UPDATE 1: Added string Position to Person and Contact classes.
UPDATE 2: Thank you all for your inputs. Given time constraints and old UI requirements, I ended up with having 2 separate classes. However, I personally like Erik Funkenbusch's alternative approach from comments below. If I'll run into a similar situation in the future, I will push for the List of objects and the "Add New Bla" button solution. I think that's the way to go.
As the Null property answer doesn't seem to be working for you, I would suggest the following model then :
public class MainContact: BaseContact
{
[Required]
[StringLength(50)]
public override string FirstName { get; set; }
[Required]
[StringLength(50)]
public override string LastName { get; set; }
}
public class BaseContact
{
[StringLength(50)]
public virtual string FirstName { get; set; }
[StringLength(50)]
public virtual string LastName { get; set; }
string Position { get; set; }
}
and then make the MainModel like so :
public class MyViewModel
{
[Required]
public MainContact MainContact { get; set; }
public BaseContact AltContact { get; set; }
}
You still need to have two different models, but you get the benefit of sharing the common elements through inheritance.
I have the following model:
public sealed class Consignor : TwoNames
{
public Consignor()
{
Address = new Address();
}
}
It's mother class TwoNames looks like this:
public abstract class TwoNames : Search
{
[Required]
public int AddressId { get; set; }
public virtual Address Address { get; set; }
[Required]
public string Name1 { get; set; }
public string Name2 { get; set; }
}
And my Address model is here:
public class Address : Model
{
[Required]
public string Street { get; set; }
[Required]
public string ZipCode { get; set; }
[Required]
public string City { get; set; }
public string Country { get; set; }
public string Email { get; set; }
}
They all inherit from "Model". Model has just an id.
Everything works well, BUT:
Lazy loading seems to be not working.
I'm loading a consignor like this:
List<Consignor> consignors = UnitOfWork.ConsignorRepository.Get().ToList();
All of the consignors got the correct AddressID and Address is not null (I guess because of my constructor in the Consignor class) but the Address property is not filled correctly (no street, no zip code, etc.).
It looks like the Consignor's constructor will instantiate a new Address object with blank street, zip, etc. (like you mentioned in your last paragraph); if you remove the instantiation of Address, you should end up with a not-loaded Address on your Consignor objects that you can lazily load as needed.