RAVEN – Eventual consistência

Trabalho em um projeto cuja uma das necessidades é ter muita velocidade de leitura das informações salvas no banco de dados.
Por conta disso resolvemos optar por um banco de dados no-cicle RAVEN DB. O Banco de dados é extremamente rápido montar querys e views do sistema, o que é ótimo contudo temos que lidar com a eventual consistência.

O que é eventual consistência?
É quando existe um agendamento para uma informação ser salva no banco de dados. Não é instantâneo. Isso é preço de ter como prioridade a leitura e não a persistência.

Como proceder quando preciso de uma informação salva para continuar um processo?
Você deve utilizar uma regra na query que garanta que todos os index foram salvos e gerados no momento da sua consulta.

No RAVENDB utilizo 2 soluções. A boa e a menos boa (ruim).

A boa é criando uma tag e informando ela no método: WaitForNonStaleResultsAsOf.
Conforme exemplo:

public Invoice Load(Guid id)
{
using (var session = _store.Open())
{
var sessionInvoice = session.Load(id);
var etag = session.Advanced.GetEtagFor(sessionInvoice);

return session
.Query()
.Customize(x => x.WaitForNonStaleResultsAsOf(etag))
.Where(i => i.Type == EPersistedInvoice.Invoice && i.Id == id)
.ToList()
.Select(ConvertToInvoice).FirstOrDefault();
}
}

E a ruim é usando o método: WaitForNonStaleResultsAsOfLastWrite(), que espera atualizar todos os index que estão na fila para serem atualizados..

Fonte: https://ravendb.net/docs/article-page/3.5/all/users-issues/understanding-eventual-consistency

Anúncios

Multi-linguagem no Angular – exemplos

Pode-se utilizar a biblioteca angular angular-translate para trabalhar com traduções de páginas feitas utilizando angular.

Bower: “angular-translate”: “2.13.0”

Dentro de uma arquitetura de sistema, sabemos que a responsabilidade de exibir as mensagens aos usuários é da tela, e nada mais justo que utilizar uma ferramenta do angular para resolver questões de multi-linguagem.

O principal argumento para responsabilizar a tela pela exibição das mensagens é porque na tela é que se estuda a melhor maneira de se apresentar uma informação, e a mesma informação pode ser exibida de maneiras diferentes em telas diferentes, por exemplo uma informação sendo exibida para celular e para computador.

No código abaixo adicionamos a referência do serviço (pascalprecht.translate) no módulo app e utilizamos a implementação config do angular para que essa configuração seja a primeira executada ao iniciar o sistema. O config do Angular não aceita a injeção de serviços, então para resolver isso usamos um provider ($translateProvider). No config utilizações 2 funções, sendo a primeira translations para informar as traduções e a  preferredLanguage para informar a linguagem padrão.

Segue a implementação em Javascript do código escrito com Angular 1, abaixo:


    var app = angular.module('app', ['pascalprecht.translate']);

    app.config(function ($translateProvider) {

        $translateProvider.translations('pt-br', {
            MENU_TITULO: 'Site',
            MENU_CAPA: 'Página inicial',
            MENU_SOBRE: 'Sobre',
            MENU_CONTATO: 'Contato'
        });

        $translateProvider.translations('en', {
            MENU_TITULO: 'Site',
            MENU_CAPA: 'Home',
            MENU_SOBRE: 'About',
            MENU_CONTATO: 'Contact'
        });

        $translateProvider.preferredLanguage('pt-br');

Segue a implementação em HTML de como usar as traduções, abaixo:

<ul class="nav navbar-nav">
	<li><a href="#">{{ 'MENU_TITULO' | translate }}</a></li>
	<li><a href="#">{{ 'MENU_CAPA' | translate }}</a></li>
	<li><a href="#">{{ 'MENU_SOBRE' | translate }}</a></li>
	<li><a href="#">{{ 'MENU_CONTATO' | translate }}</a></li>
</ul>

Para não complexificar a explicação, vou colocar meu projeto de teste em anexo.

Segue o linque do exemplo para download (zip): http://www.4shared.com/zip/YH5kRblLce/AngularTranslatePlayground.html?

Nesse projeto tenho 2 implementações.
Sendo a primeira e mais simples a que segue o exemplo acima.

E a mais complexa é utilizando cookies para salvar a linguagem selecionada e utilizando API para consultar as traduções por linguagem.
Optei por transitar na API somente 1 linguagem de cada vez por uma questão de desempenho e por salvar a linguagem em cookie pois acredito ser uma boa solução neste caso.

Javascript: Exemplo de como adicionar (push) e remover (splice) itens de um Array.

Ao trabalhar com Arrays em Javascript é muito comum ter a necessidade de Adicionar e Remover itens do Array.
Para Adicionar um item deve-se utilizar a função PUSH, onde deve-se utilizar a seguinte sintaxe: arr_nomes.push(valor) onde o arr_nomes é o array e o valor é o item a ser adicionado.
Para Remover um item deve-se utilizar a função SPLICE, onde deve-se utilizar a seguinte sintaxe: arr_nomes.splice(posicao, 1) onde arr_nomes é o array, a posição é o índice a ser removido e o numero 1 é a quantidade de itens a serem excluídos.

Veja o exemplo completo abaixo:

    <div class="container">

        <h2>Adicionar:</h2>
        <p><input type="text" id="addNome" class="form-control" placeholder="Preencher o Nome" /></p>
        <p><button type="button" class="btn btn-default" onclick="Add($('#addNome').val()); $('#addNome').val('');">Adicionar</button></p>

        <h2>Remover:</h2>
        <p><input id="removeNome" type="number" class="form-control" placeholder="Preencher o Índice" /></p>
        <p><button type="button" class="btn btn-default" onclick="Remove($('#removeNome').val()); $('#removeNome').val('');">Remover</button></p>

        <h2>Resultado:</h2>
        <div id="RETORNO" class="row" style="padding: 10px 12px;"></div>
    </div>
        var arr_nomes = ["José", "Roberto", "Maria", "Silva"];
        document.getElementById("RETORNO").innerHTML = arr_nomes;

        function Add(valor) {
            arr_nomes.push(valor);
            document.getElementById("RETORNO").innerHTML = arr_nomes;
        }

        function Remove(posicao) {
            arr_nomes.splice(posicao, 1);
            document.getElementById("RETORNO").innerHTML = arr_nomes;
        }

Angular JS – Documentação para Estudo

  • Como iniciar uma aplicação Angular
    • ng-app
    • script do AngularJS
  • Diretivas nativas do Angular
    • ng-app
    • ng-show
    • ng-hide
    • ng-if
    • ng-repeat
    • ng-controller
    • ng-model
    • ng-bind
  • Como escrever variáveis nos templates
    • {{ message }}
  • Controllers
    • app.controller(‘MainCtrl’, function($scope) {
             $scope.message = ‘Message’;
      });
  • $scope e $rootScope
  • $scope.watch

Material de Estudo AngularJS – 01

  • ANGULARJS EVENTS SYSTEM
    • $scope.
    • $on.
    • $emit.
    • $broadcast
  • BUILT-IN SERVICES
    •  $http,
    • $filter,
    • $log, …
  • FILTROS
    • “AngularJS” | uppercase
  •  ANGULAR.CONSTANT E ANGULAR.VALUE
  • DEPENDENCY INJECTION & PROMISES

Material de Estudo AngularJS – 02

  • Como criar serviços
  • HTTP Interceptors
  • angular.run & angular.config
  • Como criar diretivas
  • data-ng-app
  • $q
  • Como criar filtros
  • services vs factories

Material de Estudo AngularJS – 03

.Net Mvc C# – Cadastro de Pedido com Itens de Produto ( múltiplos registros )

Para conseguir postar um cadastro com múltiplos registros segui este tutorial:
http://dotnetawesome.blogspot.com.br/2013/09/how-to-update-multiple-row-at-once.html

Conversei com o Cleyton Ferrari e ele sugeriu utilizar AngularJs ou knockoutJS. Eles tornam o serviço mais simples nas interações com os elementos/componentes HTML, principalmente pra ir adicionando itens em uma lista. O Cleyton me indicou este código fonte dele: https://github.com/cleytonferrari/SPAAngularJS?files=1

no meu primeiro teste utilizei a model:

namespace MultiplosIntes.Models
{
    public class Pedido
    {
        [Required(ErrorMessage = "Favor preecher o Número do Pedido!", AllowEmptyStrings = false)]
        public int NumeroPedido { get; set; }
        public IList Itens { get; set; }
    }

    public class ItensPedido
    {
        public ItensPedido()
        {
            this.Produto = "";
            this.Quantidade = 0;
            this.Valor = 0;
        }

        [Required(ErrorMessage = "Favor preecher o Produto!", AllowEmptyStrings = false)]
        public string Produto { get; set; }
        [Required(ErrorMessage = "Favor preecher a Quantidade!", AllowEmptyStrings = false)]
        public int Quantidade { get; set; }
        [Required(ErrorMessage = "Favor preecher o Valor!", AllowEmptyStrings = false)]
        public decimal Valor { get; set; }
    }

}

Controller:

namespace MultiplosIntes.Controllers
{
    public class PedidoController : Controller
    {        
        public ActionResult Cadastrar()
        {
            Pedido pedido = new Pedido(); 
            pedido.Itens = new List();
            pedido.Itens.Add(new ItensPedido { Produto = "", Quantidade = 0, Valor = 0 });

            return View(pedido);
        }

        [HttpPost]
        public ActionResult Cadastrar(Pedido model)
        {
            var teste = model;

            return View(model);
        }
    }
}

View:

@model MultiplosIntes.Models.Pedido
@{
    ViewBag.Title = "Cadastrar";
}

<h2>Cadastrar</h2>

@using (Html.BeginForm())
{
    <table id="dataTable">
        <tr>
            <td>Número</td>
            <td>@Html.TextBoxFor(a=&gt;a.NumeroPedido)</td>
            <td></td>
        </tr>        
        <tr>
            <td>Produto</td>
            <td>Quantidade</td>
            <td>Valor</td>
        </tr>
        @if (Model.Itens != null &amp;&amp; Model.Itens.Count &gt; 0)
        {
            int j = 0;
            foreach (var i in Model.Itens)
            {
                <tr style="border:1px solid black;">
                    <td>@Html.TextBoxFor(a=&gt;a.Itens[j].Produto) @Html.ValidationMessageFor(a=&gt;a.Itens[j].Produto)</td>
                    <td>@Html.TextBoxFor(a=&gt;a.Itens[j].Quantidade) @Html.ValidationMessageFor(a=&gt;a.Itens[j].Quantidade)</td>
                    <td>@Html.TextBoxFor(a=&gt;a.Itens[j].Valor) @Html.ValidationMessageFor(a=&gt;a.Itens[j].Valor)</td>
                    <td>
                        @if (j &gt; 0)
                        {
                            <a href="#" class="remove">Remove</a>
                        }
                    </td>
                </tr>
                j++;
            }
        }
        
        <tr>
            <td colspan="4"></td>
        </tr>
        <tr>
            <td colspan="4"></td>
        </tr>
        <tr>
            <td colspan="4"></td>
        </tr>
    </table>
}

.Net Mvc C# – Trabalhando com Json com chamadas Ajax ($.getJSON e $.ajax)

Para trabalhar com Chamadas em Ajax e Json se faz necessário ter adicionado uma biblioteca Jquery.

Usando o Jquery você pode usar tanto a chamada $.getJSON quanto $.ajax, sendo que a primeira é um “resumo” da segunda.

Veja o Exemplo com $.getJSON :

function ConsultarStatusWs() {     
            $.getJSON("../ConsumoWS/JsonStatusWs", null, function (data) {   
                $("#Resultado").html("");
                $("#Resultado").append("<p>Transacoes=" + data.Result.Transacoes + "<br>Consumidas=" + data.Result.Consumidas + "<br>Saldo=" + data.Result.Saldo + "<br></p>");
            });
        }

Para que este exemplo funcione inicializar a função “ConsultarStatusWs()” e ter uma div “div id=”Resultado”/div”, alem é claro do de um include do jquery: “script src=”~/Scripts/jquery-2.0.3.js””

Um exemplo que possui um resultado exatamente igual ao anterior é com o uso do $.ajax:

function ConsultarStatusWsAjax() {
            $.ajax({
                dataType: "json",
                url: "../ConsumoWS/JsonStatusWs",
                success: function (data) {
                    $("#Resultado").html("");
                    $("#Resultado").append("<p>Transacoes=" + data.Result.Transacoes + "<br>Consumidas=" + data.Result.Consumidas + "<br>Saldo=" + data.Result.Saldo + "<br></p>");
                }
            });

Agora veja o Código do Controller ConsumoWS:

namespace STI.Associados.PortalWeb.Controllers
{
    public class ConsumoWSController : STIControllerBase
    {
        private IConsumoWsApp _consumoWsApp;

        public ConsumoWSController()
        {
            this._consumoWsApp = StructureMap.ObjectFactory.GetInstance<IConsumoWsApp>();
        }
        
        public ActionResult Index()
        {

            return PartialView("Index");
        }

        public JsonResult JsonListaConsumoPorMes()
        {
            IList<ConsumoWsDTO> consumo = this._consumoWsApp.GetWSTransacoesTotalisadasPorMes();
            return this.Json(new { Result = consumo }, JsonRequestBehavior.AllowGet);
        }

        public JsonResult JsonStatusWs()
        {
            StatusDTO status = this._consumoWsApp.GetWSStatus();
            return this.Json(new { Result = status }, JsonRequestBehavior.AllowGet);
        }
    }
}

A Action JsonStatusWs retorna o seguinte json:

{"Result":{"Transacoes":1000000,"Consumidas":862,"Saldo":999138}}

E a Action JsonListaConsumoPorMes retorna o seguinte json:

{"Result":[{"Mes":"2","Ano":"2015","Total":190},{"Mes":"3","Ano":"2015","Total":467},{"Mes":"4","Ano":"2015","Total":209}]}

Algumas observações importantes:
1º É interessante sempre utilizar o tipo de result da action “JsonResult”, para que você tenha certeza que essa action retornará somente um código JSON.
2º No return tem o código JsonRequestBehavior.AllowGet que é necessário para que a action receba requisições de qualquer lugar. Sem esse comando é comum encontrar o erro: ” This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet. “.

Veja no Exemplo abaixo como tratar o caso da lista de resultados.
Exemplo:

function ConsultarConsumoWs() {
            $("#Resultado").fadeOut();
            $.getJSON("../ConsumoWS/JsonListaConsumoPorMes", null, function (data) {
                $("#Resultado").fadeIn(); $("#Resultado").html("");
                $.each(data.Result, function (index, valor) {                   
                    $("#Resultado").append("<p>Consumo em " + valor.Mes + "/" + valor.Ano + ": " + valor.Total + " </p>");
                });
            });
        }

Ferramentas para Equipes de Desenvolvimento

  • IDE de desenvolvimento
    • VS2013, VS2012 e VS2010
  • Produtividade
    • ReSharper
    • Code Compare
    • ReShaper (R#)
  • Arquitetura
    • Enterprise Architect
    • Visio
  • IDE de Banco de Dados
    • Sql Server Management Studio
    • DatabaseNet4
  • Banco de Dados
    • NHibernate
    • Entity Framework
    • NHibernate Profile
    • PL/SQL
    • Glimpse
    • ErWin – Modelagem
    • RedGate ToolBelt – Intellisense para o SQL Management Studio
  • Editor de Texto
    • PSPad e Notepad++
  • Editor de Imagens
    • Paint.NET
  • Projetos
    • Microsoft Project
    • Gantter
    • Bug track – FogBuz
  • Cobertura de testes
    • dotCover
    • MSTest (integrado com R#)
    • NCRUNCH
  • Continuous Integration Server
    • TFS e Team City
    • AppVeyor e WebDeploy
    • Octopus Deploy
  • Subversion SVM
    • Tortoise
    • AnkhSVN
    • Kiln + Mercurial + TortoiseHG
  • Sniffing e simulador de requests
    • Fiddler

E você, quais ferramentas usa?