ServiceStack Locode Multi select option - servicestack

I am developing an app and got a feature where an user can assign multiple User's to a Feature . I want the Create Feature page (locode) to populate the list of available users so that the end-user can assign multiple users to a feature. As of now it is not able to populate the User list.
Is there an alternate way or do I need to write the custom template and populate the data on mount() lifecycle?
Below is the DTO,
[Route("/feature", "POST")]
public class CreateFeatureFlag : ICreateDb<Feature>, IReturn<FeatureCreated>
{
[ValidateNotEmpty]
public string Name { get; set; }
[ValidateNotEmpty]
public List<Guid> Users{ get; set; }
}
and the Domain Feature,
[UniqueConstraint(nameof(Name))]
public class Feature : AuditBase
{
[AutoId]
public Guid Id { get; set; }
public string Name { get; set; }
[Reference]
public List<User> Users { get; set; } = new();
}

In Locode it would require a custom Form component to implement it in the same form, but you can add related records by navigating to the child relation then adding the child record where it will preserve and prepopulate the parent id.
This is used a lot in https://talent.locode.dev like navigating to a Job's Job Applications defined by its POCO Reference:
public class Job : AuditBase
{
//...
public List<JobApplication> Applications { get; set; } = new();
}
Which will prepopulate the Job Id reference making it easy to add multiple 1:Many Job Applications.
Checkout its Talent.cs DTOs for more Reference examples.

Related

AutoQuery insight needed

So, I'm working with ServiceStack and love what it offers. We've come to a point where I'm needing to implement a queryable data API... prior to my coming to this project, a half backed OData implementation was done. I'd rather not try and weed through that to make it work.
Which brings me to AutoQuery. I'd like to try it with our SQL Server database. I'm looking at the examples at http://docs.servicestack.net/autoquery-rdbms - but I cannot for the life of me get this to work. Is there something I'm missing here?
I'm using ORMLite to query SQL, and my integration tests I've written show it to be working as I would expect. I have registered the OrmLiteConnectionFactory in the container, as well as my repository which uses it by way of dependency injection.
Specific to code so far, I have a type, and a message that is based on QueryDb:
public class Detail
{
public string Div { get; set; }
public string Reg { get; set; }
}
[Route("/report/detail")]
public class DetailQuery : QueryDb<Detail>
{
public string[] Div { get; set; }
public string[] Reg { get; set; }
}
The message, DetailQuery, is used by my service:
public class ReportService : Service
{
public object Get(DetailQuery dq)
{
// not sure what to put here?
}
}
With all of that, I am able to see the AutoQuery service instance in the admin interface. When I play with the query interface, I hit my service endpoint, and I see the data I expect - filter values in the 'Div' and 'Reg' collections. What am I missing for this to 'just work' here? I have done plenty in ServiceStack accessing my repositories from the Service itself, but I'm trying to gain some insight into what AutoQuery brings to the table here. I have yet to see a 'straight forward' example of how this works... or am I looking for a pot of gold that just isn't there?
AutoQuery works with just the Request DTO i.e. it doesn't need any Service implementation, so your query:
[Route("/report/detail")]
public class DetailQuery : QueryDb<Detail>
{
public string[] Div { get; set; }
public string[] Reg { get; set; }
}
When called from /report/detail will query the Detail RDBMS Table. But your properties here either need to match a column on the Detail table (e.g. Div or Reg) in order to have an exact match (default), however exact matches aren't normally done with arrays they're done with scalar values like a string, e.g:
public string Div { get; set; }
public string Reg { get; set; }
If you're querying a collection you'd be instead making an IN Query where the values would contain list of values, in which case they're normally pluralized:
public string[] Divs { get; set; }
public string[] Regs { get; set; }
and can be called with:
/report/detail?Divs=A,B&Regs=C,D
Which will perform a query similar to:
SELECT * FROM Detail WHERE Div IN ('A','B') AND Rev IN ('C','D')
If that's not the behavior you want it needs to match an implicit convention, e.g:
public string[] DivBetween { get; set; }
Which will then query:
SELECT * FROM Detail WHERE Div BETWEEN 'A' AND 'B'
If you wanted to you could override the AutoQuery service with a custom implementation, e.g:
public class MyQueryServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
//Override with custom implementation
public object Any(DetailQuery query)
{
var q = AutoQuery.CreateQuery(query, base.Request);
return AutoQuery.Execute(request, q);
}
}
But you'd only need to do that when you want to customize the default behavior, e.g. add an extra filter to the populated SqlExpression.

How to extend IdentityUserLogin in ASP.NET Identity model?

I want to extend the default functionality and for integration with social networks I want to store profile's avatar Url as well. I think it would be reasonable to extend IdentityUserLogin class that stores information about the integration but can't find any information how to do that.
Am I on the right way or it's bad idea and better to use some other solution?
Just update the model that the default MVC5 project creates for you (or create a new one if you need):
public class ApplicationUser : IdentityUser
{
public string HomeTown { get; set; }
public DateTime? BirthDate { get; set; }
}
The DB context then gets updated as such:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
}
And now, in your controller, you'll have access to the additional properties that you've added.

Option for Include to only return foreign keys

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.

How to do this in DDD without referencing the Repository from the domain entity?

I'm struggling hard to find a proper design to avoid referencing a Repository from an Entity... Let's say I've got the classic Customer and Order classes like so:
public class Customer {
...
public IEnumerable<Order> Orders { get; set; }
}
public class Order {
...
public Customer Customer { get; set; }
public IEnumerable<OrderItem> OrderItems { get; set; }
public void Submit() {
...
}
}
public class OrderItem {
public Product Product { get; set; }
public decimal SellingPrice { get; set; }
}
Now, let's say that the Product's selling price depends for some reason on the fact that the Product was also purchased (or not) on the previous Order, the number of items on the current order and previous order, etc. I could do this:
public void Submit() {
Order lastOrder = this.Customer.Orders.LastOrDefault();
CalculatePrice(lastOrder);
but that would load the whole order list of Orders when I only really need the last one!
What I'd like to do is something more like this:
public void Submit() {
Order lastOrder = _orderRepository.GetLastOrderFor(Customer);
CalculatePrice(lastOrder);
But I understand referencing the OrderRepository in the Domain is bad DDD. So, what do I do? Do I have to put the Submit() elsewhere than in the Domain? If so, where do you suggest?
You have two varieties:
Create a domain service and add a dependency to the repository from it:
public class MyPricingStrategy : IPricingStrategy
{
public MyPricingStrategy(IOrderRepository repository)
{ ... }
}
this way you will make domain service reference repository which is not very bad idea.
Another option is to make the pricing strategy a domain object with application layer passing it required data from repository:
public class LastOrderPricingStrategy
{
public LastOrderPricingStrategy(Order lastOrder)
{ ... }
}
in application layer
var lastOrder = orderRepository.GetLastOrder(currentCustomer);
var pricingStrategy = new LastOrderPricingStrategy(lastOrder);
The Customer object could have a LastOrder property:
public class Customer {
...
public IEnumerable<Order> Orders { get; set; }
public Order LastOrder { get; set; }
}
So part of the logic of making an order sets this field, and this will be saved with the Customer. Then when you load the customer, you will quickly know what the last order way, and make your decisions based on that accordingly.
Another way, if you are using an ORM like NHibernate, you could create a multi query to eagerly load the Orders collection with only the last order. then you could go back to using this:
public void Submit() {
Order lastOrder = this.Customer.Orders.LastOrDefault();
CalculatePrice(lastOrder);
and it would not need to load anything because the order you need will be in there. Eagerly loading only the objects I'm going to need in a collection is a pattern I use quite a lot.

Is instantiating a collection in a domain model considered a good practice?

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.

Resources