Separation of concerns, separate DTO from database entities

When I’m building a service I usually put my DTOs in a library I can share with the consumers of the service. Since the DTOs are my contract it is exactly what I want to do. But if I use autoquery, I have to share the enteties that map to my database model also since thats what autoquery works on.

Is it possible to avoid doing this somehow?

I have a legacy application and I have created model POCOs with aliases for this DB to invent “my new model”. I wan’t to use Auto Query but I don’t want to expose information about my backend DB. What would be the best approach here?

  • To expose the models as DTOs and decorate them with alias attributes dynamically?
  • Partials in some way?
  • Normal class inheritance?

Any Type returned in a ServiceStack Service would need to be shared for clients to have a typed API.

If you choose not to share the types, clients can access Auto Query dynamically using a basic http client, e.g:

/query-items?take=10

But they’d have to deserialize and introspect the response manually, like they would with any untyped service.

You could use Add ServiceStack Reference which will generate your DTO’s without OrmLite attributes, you can also decorate any properties [IgnoreDataMember] on your Data Model to hide them from the generated DTO.

Don’t use inheritance, and partials can’t help, but you could create a separate DTO/DataModel with just the subset of properties you want to query/return and use the [Alias] attribute to reference the underlying table.

It looks like ssutil is the way for me to go like you point out. This will enable me to keep my alias hidden from the outer world while still providing my users typed access to the service. Thank you!

1 Like

I’m returning a custom result as I didn’t want the data model to be part of the service model. If the request DTO was to inherit QueryBase<From, Into> I’d still have to expose the data model, so I took a different approach:

ServiceModel

public abstract class CustomQueryBase<T> : IQuery, IReturn<QueryResponse<T>>
{
    public Dictionary<string, string> Meta { get; set; }
    public int? Skip { get; set; }
    public int? Take { get; set; }
    public string OrderBy { get; set; }
    public string OrderByDesc { get; set; }
    public string Include { get; set; }
}

public class QueryRockstars : CustomQueryBase<CustomRockstar>
{
    public int? Age { get; set; }
}

ServiceInterface

internal class QueryRockstarsAutoQuery : QueryRockstars, IQuery<Rockstar, CustomRockstar> {}

public class QueryRockstarsService : Service
{
    public IAutoQuery AutoQuery { get; set; }

    public object Any(QueryRockstars request)
    {
        var autoQueryRequest = request.ConvertTo<QueryRockstarsAutoQuery>();
        var q = AutoQuery.CreateQuery(autoQueryRequest, Request.GetRequestParams());
        return AutoQuery.Execute(autoQueryRequest, q);
    }
}
1 Like