I'm getting started with ServiceStack and I've got to say I'm very impressed with all it has under the bonnet and how easy it is to use!
I am developing a predominantly read-only application with it. There will likely be updates to the database 3 or 4 times a year but the rest of the time the solution will be displaying data on an electronic information board (large touch screen monitor).
The database structure is well normalised with a few foreign keyed tables and with this in mind I think it may be best to separate the read only API from the CRUD API. The CRUD API can be used to create and modify the relational data with POCO classes matching the database tables. I would then ensure the read-only API flattens the relational data into a few POCOs spanning a few db tables making the data easier to handle on the read-only UIs.
I'm just looking for ideas and advice really on whether this separation of concerns is wasted effort or if there is a better way of achieving what I need? Has anyone had similar thoughts / ideas?
Having developed a similar read only application (a gazetteer, updated quarterly/yearly) using ServiceStack we went with optimizing the API for reads, making use of the built in caching:
// For cached responses this has to be an object
public object Any(CachedRequestDto request)
{
string cacheKey = request.CacheKey;
return this.RequestContext.ToOptimizedResultUsingCache(
base.Cache, cacheKey, () =>
{
using (var service = this.ResolveService<RequestService>())
{
return service.Any(request.TranslateTo<RequestDto>()).TranslateTo<CachedResponseDto>();
}
});
}
Where CacheKey is just:
public string CacheKey
{
get
{
return UrnId.Create<CachedRequestDto>(string.Format("{0}_{1}", this.Field1, this.Field2));
}
}
We did start creating a CRUD / POCO service, but for speed went with using bulk import tools such SQL Server DTS/SSIS or console apps which suffices for now, and will revisit this later if required.
Might want to consider something like CQRS.
https://gist.github.com/kellabyte/1964094 (or Google for CQRS Martin Fowler, can only post 2 links).
Also found the following article valuable recently when starting to implement additional search type services: https://mathieu.fenniak.net/stop-designing-fragile-web-apis/
Related
I am working on a project in which I need a set of data frequently and currently for getting that data I have to make call to 3rd party Service which is taking lot of time.So what I want is to maintain a local cache.The Data is modified very infrequently or is almost constant.What is the best way of implementing this in Azure Service Fabric.I am currently thinking of making the Microservice stateful. Is is the best way to do this?When node goes down it should copy its local cache to other node.If making it stateful is good than How should i go on implementing this?
Well, you have two options:
If you need performance and geografical cache data replication, you can use a redis cache.
The other option is use reliable dictionary's. It's a service fabric feature, and reliable dictionary's are replicated to other nodes.
You can only access the reliable dictionary in a service fabric statefull context.
Example bellow:
IReliableDictionary<string, string> Dictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, string>>("stringlistcache");
using (var tx = this.StateManager.CreateTransaction())
{
await pingDictionary.AddOrUpdateAsync(tx, "testkey", "testvalue", (key, value) => "testvalue");
cachedValue = await Dictionary.TryGetValueAsync(tx, "testkey");
await Dictionary.TryRemoveAsync(tx, "testkey");
await tx.CommitAsync();
}
I know this post is quite old, but for those looking for a solution today, you can use this open source project:
http://service-fabric-distributed-cache.socreate.it
you can also find it on GitHub here:
https://github.com/SoCreate/service-fabric-distributed-cache
How I can refresh spring cache when I inserted data into Database through my services and when I added data directly into database.Can we achieve this?.
Note:
I am using following libs
1)net.sf.json-lib
2)spring-support-context
through my services
This is typically achieved in your application's services (e.g. #Service application components) using the Spring #Cacheable, #CachePut annotations, for example...
#Service
class BookService {
#Cacheable("Books")
Book findBook(ISBN isbn) {
...
return booksRepository().find(isbn);
}
#CachePut(cacheNames = "Books", key = "#book.isbn")
Book update(Book book) {
...
return booksRepository.save(book);
}
}
Both #Cacheable and #CachePut will update the cache provider as the underlying method may callback through to the underlying database.
and when I added data directly into database
This is typically achieved by the underlying cache store. For example, in GemFire, you can use a CacheLoader to "read-through" (to your underlying database perhaps) on "cache misses". See GemFire's user guide documentation on "How Data Loaders Work" as an example and more details.
So, back to our example, if the "Book (Store)" database was updated independent of the application (using Spring's Caching Annotation support and infrastructure), then a developer just needs to define a strategy on cache misses. And, in GemFire that could be a CacheLoader, and when...
bookService.find(<some isbn>);
is called resulting in a "cache miss", GemFire's CacheLoader will kick in, load the cache with that book and Spring will see it as a "cache hit".
Of course, our implementation of bookService.find(..) went to the underlying database anyway, but it only retrieves a "single" book. A loader could be implemented to populate an entire set (or range) of books based on some criteria (such as popularity), where the application service expects those particular set of books to be searched for by potential customers, using the application, first, and pre-cache them.
So, while Spring's Cache annotations typically work per entry, a cache store specific strategy can be used to prefetch and, in-a-way, "refresh" the cache, lazily, on the first cache miss.
In summary, while the former can be handled by Spring, the "refresh" per say is typically handled by the caching provider (e.g. GemFire).
Hopefully this gives you some ideas.
Cheers,
John
Currently I have a project using WebAPI and EF with Breeze, it works fine with Metadata stuffs for validation on server but when migrating to NodeJS and MongoDB, I get stuck for trying get Metadata from MongoDB. I checked out zza BMEAN app but I just saw on this project:
app.get('/breeze/Breeze/Metadata', getMetadata);
function getMetadata(req, res, next) {
next({
statusCode: 404,
message: "No metadata from the server; metadata is defined on the client"
});
}
I also read all document about Breeze/MongoDB but still doesn't help me to get Metadata for this.
The main point is I just want to change backend with BMEAN instead of WebAPI+EF+Breeze, don't need to change code on client.
Thanks
The metadata is provided by EF, not by MongoDB. If you are using a CodeFirst approach with EF then you should already have a DBContext.
This talks about how to use the DBContext -
http://www.breezejs.com/documentation/entity-framework-dbcontext
This talks about how to use EF as a design tool to build your meta data from classes -
http://www.breezejs.com/documentation/ef-design-tool
Odds are you already have what you need to generate the metadata it is just extending that and exposing a service to provide it to the client.
PW Kad's answer is correct, but to clarify, there is no way to get metadata from a MongoDB database because the database itself has an indeterminate structure. So you have to tell your client what the structure is. If you want to use the same client code for EF and Mongo then saving the metadata provided by the EFContext in your Mongo project makes a lot of sense. In other cases simply define the metadata directly on the client via Breeze's metadata api calls.
I'm curious why the decision was made to couple the Service base class in ServiceStack to data access (via the Db property)? With web services it is very popular to use a Data Repository pattern to fetch the raw data from the database. These data repositories can be used by many services without having to call a service class.
For example, let's say I am supporting a large retail chain that operates across the nation. There are a number of settings that will differ across all stores like tax rates. Each call to one of the web services will need these settings for domain logic. In a repository pattern I would simply create a data access class whose sole responsibility is to return these settings. However in ServiceStack I am exposing these settings as a Service (which it needs to be as well). In my service call the first thing I end up doing is newing up the Setting service and using it inside my other service. Is this the intention? Since the services return an object I have to cast the result to the typed service result.
ServiceStack convenience ADO.NET IDbConnection Db property allows you to quickly create Database driven services (i.e. the most popular kind) without the overhead and boilerplate of creating a repository if preferred. As ServiceStack Services are already testable and the DTO pattern provides a clean endpoint agnostic Web Service interface, there's often not a lot of value in wrapping and proxying "one-off" data-access into a separate repository.
But at the same time there's nothing forcing you to use the base.Db property, (which has no effect if unused). The Unit Testing Example on the wiki shows an example of using either base.Db or Repository pattern:
public class SimpleService : Service
{
public IRockstarRepository RockstarRepository { get; set; }
public List<Rockstar> Get(FindRockstars request)
{
return request.Aged.HasValue
? Db.Select<Rockstar>(q => q.Age == request.Aged.Value)
: Db.Select<Rockstar>();
}
public RockstarStatus Get(GetStatus request)
{
var rockstar = RockstarRepository.GetByLastName(request.LastName);
if (rockstar == null)
throw HttpError.NotFound("'{0}' is no Rockstar".Fmt(request.LastName));
var status = new RockstarStatus
{
Alive = RockstarRepository.IsAlive(request.LastName)
}.PopulateWith(rockstar); //Populates with matching fields
return status;
}
}
Note: Returning an object or a strong-typed DTO response like RockstarStatus have the same effect in ServiceStack, so if preferred you can return a strong typed response and avoid any casting.
Can anyone guide me on how to setup relational schema & performs joins in sails.js?
Associations are officially Supported in Waterline
Overview
From the docs:
With Sails and Waterline, you can associate models across multiple data stores. This means that even if your users live in PostgreSQL and their photos live in MongoDB, you can interact with the data as if they lived together in the same database. You can also have associations that span different connections (i.e. datastores/databases) using the same adapter. This comes in handy if, for example, your app needs to access/update legacy recipe data stored in a MySQL database in your company's data center, but also store/retrieve ingredient data from a brand new MySQL database in the cloud.
Supported Association Types
One to Many
Many to Many
Cross-adapter Dominance
One to One
One Way
Planned Association Types
Through Associations
Original Post
I'm the author of Waterline, the ORM used in Sails. Waterline is brand
new and we are adding features all the time. Currently we don't have
support for associations but it's next on the roadmap. We worked out
an API for associations that I think most people will really like. You
can view the work in progress and the proposed API at: [Proposed Sails
Associations API][1].
We are going to tackle Associations and Transactions next and hope to
have them ready in the next month or so.
In the mean time if you are using the MySQL or PostgreSQL adapters
they both expose a raw .query() method that allows you to pass in a
hand built sql query and have it executed. I totally realize this
isn't ideal but should allow you to continue building your app while
we get support for associations and joins.
The function signature for the query method is:
Model.query(<sql query>, <optional data>, callback);
The example from particle banana works but should actually use "new" like "var instance = new User._model(values)". I'm using the following code and it works.
Accounts.query(query, function(err, accounts) {
if (err)
return fn(err);
accounts = _.map(accounts, function(account) {
return new Accounts._model(account);
});
fn(null, accounts);
});