Conforme prometido no post anterior, neste tutorial vou mostrar como criar um Helper para manipular coleções. 


Para começar caso você ainda não tenha feito, leia o post anterior que mostrar como eliminar os índices em coleções no ASP.NET MVC. Vou utilizar como exemplo as classes Pessoa (Person) e Telefones(Phone) onde pessoa pode ter 1 ou mais telefones, deve ser criada uma view separada para edição dos telefones isso é possível utilizando o Editor Templates do ASP.NET MVC.




Para utilizar você deve criar uma pasta chamada EditorTemplates, dentro da pasta você adiciona uma view com o mesmo nome do Model, que neste exemplo é Phone. Crie a view conforme o exemplo abaixo:


A divs que envolvem os campo não são obrigatórias.

Na view de criação, do modelo Person, você deve referenciar o editor dos telefones, conforme exemplo abaixo: 


Vamos agora a criação do Helper. Crie uma classe static com o nome de  HtmlHelpers. Dentro dessa classe crie um método conforme o exemplo abaixo:


Esse será o método responsável por adicionar mais um campo. Esse método é uma extenção da classe HtmlHelper, e recebe como parâmetros o nome que deve aparecer no link, o contêiner onde o novo campo será incluído, o nome da coleção e o tipo da coleção.

Na 1ª linha é criada uma instancia da coleção utilizando o tipo da mesma.


Na 2ª linha cria-se a view que será adicionada. Essa linha faz uma chamada para o método JsEnconde, que serve para fazer ajustes no html gerado, o código desse método é um pouco extenso e como o código será disponibilizando não vou mostrar ele aqui.


Na 3ª linha é feito um replace para adicionar o nome correto da propriedade ao campo.  

Na 4ª linha é criado a chamada da função Javascript que será a responsável por de fato adicionar o novo campo.

Conforme vimos acima o campo será adicionado via Javascript, para isso crie um script e adicione a seguinte função:


Voltando ao helper, adicione as linhas a seguir:

Nas linhas acima é feita a criação do elemento link, recebendo como parâmetros o nome do link e a chamada para a função Javascript. 

Na view faça referência ao helper e ao model.


Logo após faça a chamada do helper. Observe que o parâmetro referente ao contêiner nada mais é que o id de onde será adicionado os novos campos.

Na 2ª parte vou demostrar o procedimento para remover e as validações dos novos campos.

O projeto completo está aqui: https://github.com/rafaelguinho/AddRemove

Venho aqui trazer um assunto relativamente avançado, que a questão do Bind de coleções no ASP.NET MVC. Há duas forma de se recuperar coleções aninhadas da view no controller, a primeira é utilizado um índice sequencial:

Campos na view:



Recuperação no controller:

A segunda forma permite utilizar um índice não-sequencial alfanumérico:


Neste segundo exemplo é necessário incluir um campo do tipo "hidden", para cada campo de entrada de valor, com o value sendo o índice. Apesar dessa segunda opção ser mais versátil é limitada pois o índice ainda precisar ser único.  

Depois de estudar e pesquisar muito vi que era possível criar um bind customizado, então porque não criar um para eliminar os índices e recuperar as coleções?
No bind é possível ter acesso ao form que foi submetido, isso possibilitou ter acesso a todas as propriedades do formulário e seus valores:


Não vou me aprofundar no código do bind, o mesmo está disponível para estudo e melhorias no projeto: https://github.com/rafaelguinho/collectionbinder. Para utilizar copie a classe da pasta Binders para seu projeto e no Global.asax.cs adicione uma linha para cada coleção:

Na sua view as coleções agora podem ter todas o mesmo nome, que deve ser "NomeDaColeção.Atributo" conforme exemplo:

No próximo post eu vou mostrar como "automatizar" o processo de adicionar e remover utilizando um Helper. Até mais!

Porque é importante?

Como todos sabem, Programação Assíncrona é muito importante porque tem como objetivo principalmente aperfeiçoar a capacidade de resposta de nossas aplicações. O .NET sempre tem tentando apoiar esta forma desde sua primeira versão e sempre houveram novos recursos em cada release e apresentações de novas maneiras de assincronismo. Todas estas funcionalidades estão fora do escopo deste artigo, mas aqui estão vários recursos falando com detalhes sobre eles e descrevendo o seu uso com detalhes.
No entanto, nós desenvolvedores costumamos escrever métodos, eu digo métodos síncronos e tentamos chama-los assincronamente, de várias maneiras (Thread, ThreadStart, ThreadPool, BackgroundWorker, etc), mas a escrita de métodos assíncronos naturalmente foi difícil de fazer e manter.
O recurso pode ser resumido pelo seguinte exemplo: nós mudaremos o método para assíncrono naturalmente apenas alterando o seu tipo de retorno.

public static IEnumerable<int> getPrimes(int min, int count)
{
    return Enumerable.Range(min, count).Where
      (n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i =>
        n % i > 0));
}

Dependendo dos parâmetros min e count esse método pode durar um bom tempo. Uma maneira de torna-lo assíncrono é simplesmente trocando o tipo de retorno como no exemplo a seguir:
 
public static Task<IEnumerable<int>> getPrimesAsync(int min, int count)
{
     return Task.Run (()=> Enumerable.Range(min, count).Where
      (n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i =>
        n % i > 0)));
}

No exemplo acima, notem que nós mudamos o nome do próprio método adicionando Async como prefixo e essa é a regra que devemos seguir. Como vocês podem ver o retorno é uma Task, anteriormente era void e foi mudado para Task<T> onde T é o tipo de retorno do método.

O que é Task ?

Task é simplesmente uma implementação de  IAsyncResult .
Agora quando um método retorna Task<T> ele fica no estado awaitable isso significa que você pode chama-lo usando a keyword await, e sempre que você usar await o controle da execução voltará imediatamente e não haverá impacto na capacidade de resposta da sua aplicação.

Vamos ver como nós chamamos esses métodos acima:

private static void PrintPrimaryNumbers()
{
    for (int i = 0; i < 10; i++)
        getPrimes(i * 100000 + 1, i * 1000000)
            .ToList().
            ForEach(x => Trace.WriteLine(x));
}

PrintPrimaryNumbers() é um método que podemos chamar diretamente e tradicionalmente, neste exemplo estou chamando o método 10 vezes, ele será chamado consequentemente e nós veremos quanto tempo demora até ele ser finalizado.

private static async void PrintPrimaryNumbersAsync()
{ 
    for (int i = 0; i < 10; i++)
    {
        var result = await getPrimesAsync(i * 100000 + 1, i * 1000000);
        result.ToList().ForEach(x => Trace.WriteLine(x));
    }
}

Enquanto PrintPrimaryNumbersAsync() é decorado pela keyword async ele chama getPrimesAsync()” de forma assíncrona. Uma vez que é chamado, a execução imediatamente retorna para a thread principal e uma vez que qualquer uma das outras threads é finalizada, a thread principal terá o controle de volta (no nosso caso, escrever os números principais que podem ser encontrados no intervalo fornecido).


Agora veremos o código Main:
static void Main(string[] args)
{
 
    DateTime t1 = DateTime.Now;
    PrintPrimaryNumbers();
    var ts1 = DateTime.Now.Subtract(t1);
    Trace.WriteLine("Finished Sync and started Async");
    var t2 = DateTime.Now;
    PrintPrimaryNumbersAsync();
    var ts2 = DateTime.Now.Subtract(t2);
 
    Trace.WriteLine(string.Format(
      "It took {0} for the sync call and {1} for the Async one", ts1, ts2));
 
    Trace.WriteLine("Any Key to terminate!!");
  
}
 
Você pode me dizer a diferença entre ts1 e ts2 ?
Aqui está o resultado :
Finished Sync and started Async
 
Demorou 00:32:16.1627422 para a chamada síncrona e 00:00:00.0050003 para a chamada assíncrona.



Muitos já devem ter se deparado com situações onde se faz necessário que apenas não mais que uma coluna da tabela seja trazida, o Hibernate oferece uma solução pra isso usando HQL. Para isso vamos usar a Classe Consulta como exemplo, ela tem um relacionamento com a Classe médico e desejamos trazer todos os horário com consultas ativas de um determinado médico em um determinado dia.


Crie a seguinte query HQL:


StringBuffer hql = new StringBuffer();

hql.append("SELECT hora FROM Consulta ");

hql.append("WHERE crm_medico=:crm ");

hql.append("AND status=:status ");

hql.append("AND data=:data ");


Nessa query fazemos a seleção apenas da coluna hora, que é o dado buscado, e mais abaixo declaramos os parâmetros.


Crie a query e a transação:


Transaction tx = session.beginTransaction();

Query query = session.createQuery(hql.toString());


Passe os parâmetros:


SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

query.setString("crm", crm);

query.setBoolean("status", true);

query.setString("data", sdf.format(data));


Note que usamos um SimpleDateFormat na data e passamos a mesma como string na nossa query.


Por fim faça o commit e passe a lista retornada para uma lista do tipo de dado buscado no nosso caso uma lista de Date.


tx.commit();

horarios=(List<Date>) query.list();



Imagine a seguinte situação: Precisamos relacionar duas tabelas, clínica e médico, sendo que nesse relacionamento eu desejo guardar a data que o médico foi vinculado aquela clínica. No nosso exemplo vamos partir do ponto que já tenhamos o médico e a clinica devidamente mapeados e registros de ambos inseridos no banco.


Crie uma classe como exemplo abaixo:


@SuppressWarnings("serial")

@Embeddable

public class Clinica_MedicoPK implements Serializable{

@ManyToOne (fetch = FetchType.EAGER )

@JoinColumn (name= "cnpj_clinica" )

@OnDelete(action = OnDeleteAction.CASCADE)

@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

private Clinica clinica;

@ManyToOne (fetch = FetchType.EAGER )

@JoinColumn (name= "crm_medico" )

@OnDelete(action = OnDeleteAction.CASCADE)

@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

private Medico medico;

@Temporal(TemporalType.DATE)

private Date data_cadastro;


Temos então uma instancia da classe Clinica e uma da classe Medico como também uma instancia da classe Date que irá guardar a data de cadastro. Se você já notou temos a anotação @Embeddable, que indica que essa classe funciona com uma chave composta para uma tabela. Feito isso crie outra classe como o exemplo abaixo:


@Entity

@Table (name= "clinica_medico")

public class Clinica_Medico implements Serializable{

@EmbeddedId

private Clinica_MedicoPK clinica_MedicoPK;


public Clinica_MedicoPK getClinica_MedicoPK() {

return clinica_MedicoPK;

}


public void setClinica_MedicoPK(Clinica_MedicoPK clinica_MedicoPK) {

this.clinica_MedicoPK = clinica_MedicoPK;

}


}

Essa será nossa tabela com uma instancia de Clinica_MedicoPK que será chave composta da tabela clinica_medico.


Abaixo temos uma exemplo de como inserir:


//a clinica e o médico já inseridos no banco

Clinica clinica = repositorio.buscarClinica(id_clinica);

Medico medico = repositorio.buscarMedico(id_medico);


Clinica_MedicoPK clMedicoPK = new Clinica_MedicoPK();

//seto a clinica no pk

clMedicoPK.setClinica(clinica);

//seto o médico

clMedicoPK.setMedico(medico);

//seto a data de cadastro

clMedicoPK.setData_cadastro(new Date(System.currentTimeMillis()));

//instacio a classe que vai conter o pk

Clinica_Medico clinica_Medico = new Clinica_Medico();

//adiciono a pk com a clinica e o médico

clinica_Medico.setClinica_MedicoPK(clMedicoPK);


//insiro no banco o vínculo da clinica com o medico

repositorio.salvarClinicaMedico(clinica_Medico);

Category

Category

  • (1)
  • (1)
  • (1)
  • (1)
  • (1)
  • (1)

Category

Category