I'd like to be able to project/map properties from either of 2 child classes.
Imagine a parent class that has 2 child classes, either of 1 which points to a child class. Each child class must map to properties on the model class.
However, if child class 1 is null then it shouldn't map across to the model it should map class 2 properties instead.
It's like what I want to do here except do it across a whole class of properties rather than 1 property:
Conditonal projection
I was hoping I don't have to create a CustomResolver for each class property and whether there is a better way of achieving this. Imagine that the child classes have 10 identical properties each, all I want to do is switch the map depending on which child class is populated.
public class Message
{
public string Comment { get; set; }
public Inbound? InboundMessage { get; set; }
public Outbound? OutboundMessage { get; set; }
}
public class Inbound
{
public string Body { get; set; }
// 10 properties...
}
public class Outbound
{
public string Body { get; set; }
// 10 properties...
}
public class MessageModel
{
public string Comment { get; set; }
public string Body { get; set; }
// 10 properties....
}
Surprised no-one had an answer to this so answered myself by the time I worked out what to do.
If you have the need to conditionally map properties depending on whether a child class is populated or not, or any other logic for the whole class for that matter, then you can use a TypeConverter.
Inside the TypeConverter, you test the source parameter in the ConvertCore function, and then call Mapper.Map on the correct source to pass the child class properties out to the model.
The return from mapper can be then returned back out which will be the destination.
I never realised that you can still call Mapper.Map() even in the TypeConverter.
Related
I am running into an issue while looking at SS.
I am writing a custom Stripe implementation and got stuck on web hooks, this in particular:
https://stripe.com/docs/api#event_object
data->object - this can be anything.
Here is my DTO for it:
public class StripeEvent
{
public string id { get; set; }
public StripeEventData data { get; set; }
public string type { get; set; }
}
[DataContract]
public class StripeEventData
{
[DataMember(Name = "object")]
public object _object { get; set; }
}
My hope is to basically just get that object as a string, and then parse it:
var invoice = (StripeInvoice)JsonSerializer.DeserializeFromString<StripeInvoice>(request.data._object.ToString());
Unfortunately the data that is returned from ToString does not have quotes surrounding each json property's name:
Capture
So, the DeserializeFromString returns an object that has everything nulled out.
Why does SS internally strip the quotes out? Is this the proper way to handle a json member that can be one of many different types? I did try the dynamic stuff, but did not have any luck with that either - basically the same result with missing quotes.
I searched very thoroughly for the use of objects and dynamic within DTOs, but there really was nothing that helped with this question.
Thank you!
The issue is that you should never have an object type in DTOs as the serializer has no idea what concrete type to deserialize back into.
The Stripe documentation says object is a hash which you should be able to use a Dictionary to capture, e.g:
public class StripeEventData
{
public Dictionary<string,string> #object { get; set; }
}
Or as an alternative you could use JsonObject which provides a flexible API to access dynamic data.
This will work for flat object structures, but for complex nested object structures you'll need to create Custom Typed DTOs, e.g:
public class StripeEventInvoice
{
public string id { get; set; }
public StripeEventDataInvoice data { get; set; }
public string type { get; set; }
}
public class StripeEventData
{
public StripeInvoice #object { get; set; }
}
I have a question relating to nested results using ServiceStack's Autoquery.
Specifically,
Firstly,
I have two classes. A Parent class with a referenced list of children, as shown below:
[Alias("view_parent")]
public class ParentView
{
public int Id { get; set; }
public string ParentName {get;set;}
[Reference]
public List<ChildView> Children {get;set;}
}
[Alias("view_children")]
public class ChildView
{
[References(typeof (ParentView))]
public int ParentId { get; set; }
public string ChildName {get;set;}
}
Secondly, I have an Autoquery class as follows:
[Route("/parents", "GET")]
public class GetParents : QueryBase<ParentView>
{
}
Given the above,
Does AutoQuery support searching within the List of children from the ParentView?
e.g. the API query
/parents?ChildName=Tom
does not seem filter the results. Does AutoQuery automatically support searching within a List?
Thanks & by the way ServiceStack is pretty awesome!
AutoQuery doesn't include any child references as part of the query. You'll need to explicitly Join tables you want included in the executed query.
Does Entity Framework provide an option to retrieve child objects that are only populated with fields that are foreign keys to the parent object?
Sample code might illustrate this better.
Assuming you have the following POCO classes...
public abstract class Base
{
public Guid Id { get; set; }
}
public class User : Base
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Photo : Base
{
public string Description { get; set; }
public User UploadedBy { get; set; }
}
... and assuming you've configured a DbContext correctly, how do you query for a list of all Photos including the UploadedBy object, but where that UploadedBy object only contains the Id property?
I know I can do this...
return await _dbContext.Photos.Include(p => p.UploadedBy).ToListAsync();
... but that returns the entire User object.
I'd like to do something like this...
return await _dbContext.Photos.Include(p => p.UploadedBy.Id).ToListAsync();
... to indicate that I only want the Id property back.
If we could chain those includes we would be able to pick each property on the child object that we want returned.
Or even better, I'd love to be able to configure a setting at a more global level that would make it so that anytime I ask for Photos, give me all members of photos, even child objects, but only populate their foreign keys and nothing more.
The last request is less important though because I could just create the following extension method for each POCO object...
public static IQueryable<Photo> IncludeForigenKeys(this PhotoAlbumDbContext context){
return context.Photos
.Include(photo => photo.UploadedBy.Id);
}
As far as I understand there is no way to partially load a Navigation Property.
However for foreign keys the standard way of accessing these without loading the Nav property is to include the actual key in your model. Eg:
public class Photo : Base
{
public string Description { get; set; }
public int UploadedById { get; set; }
public User UploadedBy { get; set; }
}
This id will be populated even if you don't actually load the whole navigation property.
In the case where you load both you can update either the value on the local or remote end of the nav property and that update will be persisted to the database on save. In my experience EF is very clever around this. The only scenario where it becomes a little more tricky is in unit tests where EF is not maintaining this state.
I see these types of model is many samples online.
public class User
{
public long Id { get; set; }
public string Name{ get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Is it considered a good practice to instantiate a collection in the constructor like the code below? If so what are the reasons? How about objects in the model?
public class User
{
public User()
{
Products = new List<Product>();
}
public long Id { get; set; }
public string Name{ get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Well, I would say it depends on the situation, but Products in this case would be filled from the database, via a repository, so most probably ORM of some sort, so no initialization to new List would be needed in the constructor. The meaning of null for Products is indicative that the list isn't loaded yet. On the other hand, let's say that your object must have this collection initialized. For simple objects DDD says constructors are perfectly fine to to these things, but in case of complex objects, move the construction to the Factory.
How do restrict access to a class property to within the same namespace? Consider the following class. The Content class cannot Publish itself, instead the ContentService class
will do a few things before changing the state to published.
public class Content : Entity, IContent
{
public string Introduction { get; set; }
public string Body { get; set; }
public IList<Comment> Comments { get; set; }
public IList<Image> Images { get; private set; }
public State Status { get; }
}
public class ContentService
{
public IContent Publish(IContent article)
{
//Perform some biz rules before publishing
article.Status = State.Published;
return article;
}
}
How can i make it so only the ContentService class can change the state of the article?
Are there any deisng patterns to help me deal with this?
You can use the "internal" access modifier so that only classes within the same Assembly can modify the Content class's State member (but everyone even in other assemblies can GET the value).
public State Status { get; internal set; }
So now ContentService can set the state because it is in the same Assembly, but outside callers can only get the state (they're not allowed to set it).
Java has the notion of "package visible" or "package private". This is in fact the default for anything where you don't specify a visibility (private or public). For some reason, almost no one ever uses this.
Declare ContentService as a friend?
Alternatively, Java has an access modifier that amounts to "package-private".