Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

ASP.NET MVC Views com Listas de Objetos

Ola, enquanto eu estava vendo varios cursos sobre ASP.NET, me encountrei com problemas para expandir as Views de modelos mais complexos de implementar, com listas de objetos e sub-objetos.

Por exemplo, um objeto Livro tem uma lista de objeto Bookmarks. Dentro de Bookmark, eu poderia referenciar outros Bookmarks e/ou especificar linhas da pagina com outros objetos.

public class Livro {
    // outros parametros
    private Livro LivroProx;
    private Livro LivroAnt;
    private Bookmark[] Bookmarks
}
public class BookMark {
    // outros parametros
    private BookMarks[] Referencias;
    private Linha Quotacao;
}

Neste exemplo, eu teria de criar os objetos BookMark/Linha dentro da View de Livro/Create.cshtml, adicionar campos adicionais para inserir dados sobre Livros/Bookmarks e prover a capabilidade de Adicionar/Remover esses sub-objetos.

Pelo o que vi em varios videos da Alura, e varios artigos no Google, eu precisaria implementar varios elementos dinamicos dentro da minha View, usando Ajax/jQuery/JavaScript/.chtml.cs/etc. Estou bem confuso sobre qual implementacao eh a mais facil de fazer, funciona apropriadamente com o banco de dados e funcione com ajax(sem reloads), sem me importar muito sobre eficiencia neste momento.

Alguem poderia me dar uma ajuda ou prover mais informacao neste topico? Estou tentando varias coisas que o meu codigo praticamente virou uma sopa de letrinhas.

Grato,

Lucas

4 respostas

Oi Lucas, tudo bom?

Realmente, quando a gente começa a relacionar mais entidades o CRUD começa a ficar menos trivial.

No seu caso, a funcionalidade que você está procurando é a de criar instancias em cascata através dos relacionamentos (cascade Persist).

A funcionalidade em sí varia bastante de linguagem pra linguagem. Dei uma pesquisada aqui e não encontrei nada pronto no front pra automatizar esse processo. Então, você tem duas opções.

Uma é apenas apontar os relacionamentos no front (aqui vai os ajax) e a outra é criar realmente todos em uma tela só e persistir no final.

No primeiro caso, a abordagem é realizar os cruds de todas as entidades no back-end normalmente e utilizar as requisições para selecionar quais deles você quer na entidade.

No segundo, a abordagem é muito semelhante a de criar uma instância nova a partir do formulário. O ideal aqui é tentar utilizar o máximo possivel o ModelBind para montar a instancia pra você. Ou seja, seguir um padrão de nomenclatura nos names dos inputs do form pra facilitar a montagem da instancia com todos os relacionamentos =)

No pior dos casos, você também pode receber os parametros sem ModelBind e montar manualmente a instancia completa.

Aqui vai ficar dificil fugir do javascript porque se você quer poder adicionar/remover elementos relacionados, você vai precisar selecionar multiplos elementos no front e a unica tag que permite esse tipo de abordagem é a <select multiple>, que não te permitiria a criação em cascata.

Esse procedimento, como eu comentei, não é tão trivial assim então vai dar um trabalho mesmo no começo. Mas, depois de fazer uma ou duas vezes você já fica mais calejado =)

Abraço!

Obrigado pela a ajuda, andei brincando com o meu DbContext e parte do default ModelBind para manter os meus Nested Models. Somente que estou tendo problemas para adicionar Modelos dentro no Modelo (Bookmarks dentro Books).

Eu estava seguindo este guia Nested Models Part 2, na parte relevante a adicionar o bloco HTML para Adicionar Modelos, ando tendo problemas de geracao desse codigo HTML. Aqui segue o codigo relevante:

HtmlHelpers.cs        

public static IHtmlContent AddLink<T>(this IHtmlHelper<T> htmlHelper, string linkText, string container, string counter, string collection, Type nestedType)
{
    var ticks = DateTime.UtcNow.Ticks;
    var nestedObject = Activator.CreateInstance(nestedType);
    var partial = htmlHelper.EditorFor(x => nestedObject).ToString().JsEncode();
    var partial = partial.Replace("id=\\\"nestedObject", "id=\\\"" + collection + "_" + ticks + "_");
    partial = partial.Replace("name=\\\"nestedObject", "name=\\\"" + collection + "[" + ticks + "]");
    var js = string.Format("javascript:addNestedForm('{0}', '{1}', '{2}', '{3}'); return false;", container, counter, ticks, partial);
    TagBuilder tb = new TagBuilder("a");
    tb.Attributes.Add("href", "#");
    tb.Attributes.Add("onclick", js);
    tb.TagRenderMode = TagRenderMode.Normal;
    tb.InnerHtml.Append(linkText);
    HtmlContentBuilder result = new HtmlContentBuilder();
    return result.AppendHtml(tb);
}

O Erro deste metodo gera a string Microsoft.AspNetCore.Mvc.ViewFeatures.StringHtmlContent que quebra a logica de geracao do codigo HTML, utilizado pela minha View. Na minha View, somente aparece esta string onde o novo bloco de Bookmark deveria estar.

Pelo o que percebi durante debugging, essa String eh gerada pela linha var nestedObject = Activator.CreateInstance(nestedType);. Mas todo input alimentado ao metodo esta com valores corretos, sempre resultando na mesma mensagem.

Eu verifiquei a documentacao do Activator, mas nao encontrei nenhuma resposta. Voce tem alguma idea de como solucionar este problema ou debugar melhor este metodo?

solução!

Opa, tudo bom luke?

Você pode obedecer o seguinte fluxo ao implementar um CRUD:

CSHTML -> JavaScript -> Controller -> Service

Vamos aos passos:

No CSHTML, você poderá ter o Razor para enviar o formulário.

No JavaScript, a Requisição Ajax, por JQuery ou por JS.

No Controlador, terá os métodos que serão chamados a partir das requisições OU a partir do Razor.

O Serviço fica conectado então ao controlador, possuindo os métodos.

Para entender melhor o controlador/serviço, você teria isso:


LivroController { 
       CapturarUltimaPagina(long? id){
          return new LivroServico.CapturarUltimaPagina(id);
        } 
} 

Agora, para finalizar, existem N ferramentas para lidar com o banco de dados, o próprio EF6 possui.

Então fica a seu critério decidir utilizar o próprio EF6 ou senão, utilizar o Dapper com o Dapper Extensions.

É bem simples de fazer, após aprender isso, você será capaz também de produzir um Repositório Genérico, que servirá para tuas próximas aplicações.

Boa sorte com os estudos.

Agradeco as repostas dos dois, boa semana para todos.