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

More than one DbContext was found. Specify which one to use.

Depois de mapeado a classe Categoria e Produto no arquivo EntidadesContext executei o comando

Add-Migration no Package Manager Console e obtive o erro

More than one DbContext was found. Specify which one to use.

Não encontrei nenhuma dúvida no Fórum e recorrendo ao Docs Microsoft:

https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/powershell

Cheguei a solução:

PM> Add-Migration criaProdutoECategoria -Context EntidadesContext

Depois, obtive o mesmo erro quando executei o comando:

PM> Update-Database More than one DbContext was found. Specify which one to use.

Seguindo o raciocínio, a solução foi:

PM> Update-Database -Context EntidadesContext Applying migration '20170227061611_criaProdutoECategoria'. Done. PM>

Por que obtive esses erros? No vídeo o erro não ocorreu.

Obrigado.

8 respostas

Olá Freedy,

verifique se nos usings das classes do entity framework está aprecendo o namespace Microsoft.EntityFrameworkCore ou EntityFramework. Dando uma pesquisada, pode ser que na hora de instalar o entity framework 7 já veio o novo Entity do .Net Core que pede a passagem de qual o context você fará as migrations. Aqui um link com essa discussão.

Para testar, fiz uma implementação na loja virtual. Hoje em dia, você pode pagar uma venda com um ou dois cartões de crédito diferentes.

Nesse caso, criei 3 classes:

// podemos ter visa, mastercar, dinners.... public class BandeiraCartaoCredito { public int ID { get; set; } public string Nome { get; set; }

public int CartaoCreditoID { get; set; } public virtual IList CartaoCredito { get; set; } }

// 2 cartões de créditos diferentes podem fazer parte de uma mesma venda e o mesmo cartão de crédito pode estar em várias vendas public class CartaoCredito { public int ID { get; set; } public string Numero { get; set; } public int MesValidade { get; set; } public int AnoValidade { get; set; } public string Nome { get; set; } public int CodVerificacao { get; set; }

public int ClienteID { get; set; } public virtual Usuario Cliente { get; set; }

public int BandeiraID { get; set; } public virtual BandeiraCartaoCredito Bandeira { get; set; }

public virtual IList VendaCartaoCreditos { get; set; } }

// Para saber se a venda foi feita com cartão de crédito e quantos cartões foram usados:

public class VendaCartaoCredito { //public int ID { get; set; }

public int VendaID { get; set; } public virtual Venda Venda { get; set; }

public int CartaoCreditoID { get; set; } public virtual IList CartaoCredito { get; set; } }

Depois disso, mapeei no EntidadesContext:

public DbSet Bandeiras { get; set; } public DbSet CartaoCredito { get; set; } public DbSet VendaCartaoCreditos { get; set; }

Acrescentei o using EntityFramework; em todas as entidades, inclusive no EntidadesContext.cs e, mesmo assim, ele pediu qual DbContext eu deveria espeficar:

PM> add-migration criaBandeiraCartaoCreditoVendaCartao More than one DbContext was found. Specify which one to use.

Pergunta:

1) Se realmente agora temos que especificar o contexto, porque no vídeo da aula não foi pedido? O vídeo é muito antigo?

2) Baseando nesse raciocínio que passei, criei certo as classes e os seus relacionamentos? Poderia me corrigir, caso tenha feito algo errado?

Obrigado.

Ah, para testar se faltava instalar alguma coisa, executei o comando:

PM> Install-Package Microsoft.EntityFrameworkCore.Tools -Pre

Mas o resultado não foi satisfatório:

Attempting to resolve dependency 'Microsoft.EntityFrameworkCore.Design (≥ 1.1.0)'. Attempting to resolve dependency 'Microsoft.AspNetCore.Hosting.Abstractions (≥ 1.1.0)'. Attempting to resolve dependency 'Microsoft.AspNetCore.Hosting.Server.Abstractions (≥ 1.1.0)'. Attempting to resolve dependency 'Microsoft.AspNetCore.Http.Features (≥ 1.1.0)'. Attempting to resolve dependency 'Microsoft.Extensions.Primitives (≥ 1.1.0)'. Attempting to resolve dependency 'NETStandard.Library (≥ 1.6.1)'. Install-Package : 'NETStandard.Library' already has a dependency defined for 'Microsoft.NETCore.Platforms'. At line:1 char:1 + Install-Package Microsoft.EntityFrameworkCore.Tools -Pre + ~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Install-Package], InvalidOperationException + FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.InstallPackageCommand

Em tempo:

Quando executei:

PM> add-migration criaBandeiraCartaoCreditoVendaCartao -Context EntidadesContext

Obtive:

System.InvalidOperationException: The navigation 'VendaCartaoCreditos' on entity type 'lojaComEntity.Entidades.CartaoCredito' has not been added to the model, or ignored, or target entityType ignored. at Microsoft.Data.Entity.Metadata.Conventions.Internal.PropertyMappingValidationConvention.Apply(InternalModelBuilder modelBuilder) at Microsoft.Data.Entity.Metadata.Conventions.Internal.ConventionDispatcher.OnModelBuilt(InternalModelBuilder modelBuilder) at Microsoft.Data.Entity.Metadata.Internal.InternalModelBuilder.Validate() at Microsoft.Data.Entity.ModelBuilder.Validate() at Microsoft.Data.Entity.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator) at Microsoft.Data.Entity.Infrastructure.ModelSource.<>cDisplayClass8_0.b0(Type k) at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory) at Microsoft.Data.Entity.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator) at Microsoft.Data.Entity.Internal.DbContextServices.CreateModel() at Microsoft.Data.Entity.Internal.LazyRef1.get_Value() at Microsoft.Data.Entity.Internal.DbContextServices.get_Model() at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c.<AddEntityFramework>b__0_5(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.FactoryService.Invoke(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.ScopedCallSite.Invoke(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass12_0.<RealizeService>b__0(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetService[T](IServiceProvider provider) at Microsoft.Data.Entity.Design.Internal.DesignTimeServicesBuilder.<>c__DisplayClass7_0.<ConfigureContextServices>b__8(IServiceProvider _) at Microsoft.Extensions.DependencyInjection.ServiceLookup.FactoryService.Invoke(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.TransientCallSite.Invoke(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ConstructorCallSite.Invoke(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.TransientCallSite.Invoke(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass12_0.<RealizeService>b__0(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.Data.Entity.Design.MigrationsOperations.AddMigration(String name, String outputDir, String contextType) at Microsoft.Data.Entity.Design.OperationExecutor.<AddMigrationImpl>d__7.MoveNext() at System.Linq.Buffer1..ctor(IEnumerable1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source) at Microsoft.Data.Entity.Design.OperationExecutor.OperationBase.<>cDisplayClass4_0`1.b0() at Microsoft.Data.Entity.Design.OperationExecutor.OperationBase.Execute(Action action) The navigation 'VendaCartaoCreditos' on entity type 'lojaComEntity.Entidades.CartaoCredito' has not been added to the model, or ignored, or target entityType ignored.

Alterei a classe VendaCaraoCredito, retirando o IList e descomentei o ID (achei que não ia ser necessário, mas foi). Ficando:

public class VendaCartaoCredito { public int ID { get; set; }

public int VendaID { get; set; } public virtual Venda Venda { get; set; }

public int CartaoCreditoID { get; set; } public virtual CartaoCredito CartaoCredito { get; set; } }

Executei o comando novamente:

PM> add-migration criaBandeiraCartaoCreditoVendaCartao -Context EntidadesContext

e deu certo:

To undo this action, use Remove-Migration.

Mas, quando fui aplicar o update:

PM> update-database -Context EntidadesContext

Applying migration '20170302013406_criaBandeiraCartaoCreditoVendaCartao'. System.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN KEY constraint 'FK_Venda_Usuario_ClienteID' on table 'Venda' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.<>c.<ExecuteNonQuery>b__13_0(DbCommand cmd, IRelationalConnection con) at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.Execute[T](IRelationalConnection connection, Func3 action, String executeMethod, Boolean openConnection, Boolean closeConnection) at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, Boolean manageConnection) at Microsoft.Data.Entity.Storage.RelationalCommandExtensions.ExecuteNonQuery(IEnumerable1 commands, IRelationalConnection connection) at Microsoft.Data.Entity.Migrations.Internal.Migrator.Execute(IEnumerable1 relationalCommands) at Microsoft.Data.Entity.Migrations.Internal.Migrator.Migrate(String targetMigration) at Microsoft.Data.Entity.Design.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType) at Microsoft.Data.Entity.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String contextType) at Microsoft.Data.Entity.Design.OperationExecutor.UpdateDatabase.<>cDisplayClass0_1.<.ctor>b0() at Microsoft.Data.Entity.Design.OperationExecutor.OperationBase.Execute(Action action) ClientConnectionId:d39dde93-fcea-468c-a200-2b42214ef517 Error Number:1785,State:0,Class:16

-- essas linhas estão em vermelho-- Introducing FOREIGN KEY constraint 'FK_Venda_Usuario_ClienteID' on table 'Venda' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors. -- essas linhas estão em vermelho --

Na última linha do Up, comentei o onDelete e alterei para onUpdate (espero que tenha feito certo):

migrationBuilder.AddForeignKey( name: "FK_Venda_Usuario_ClienteID", table: "Venda", column: "ClienteID", principalTable: "Usuario", principalColumn: "Id", //onDelete: ReferentialAction.Cascade); onUpdate: ReferentialAction.Cascade);

Ao executar o comando, obtive sucesso na execução:

PM> update-database -Context EntidadesContext Applying migration '20170302013406_criaBandeiraCartaoCreditoVendaCartao'. Done. PM>

Quando fui olhar as tabelas, verifiquei que na BandeiraCartaoCredito, foi criado o CartaoCreditoID. Errei na programação.

1) Fiz a alteração na Classe BandeiraCartaoCredito retirando o CartaoCreditoID:

public class BandeiraCartaoCredito { public int ID { get; set; } public string Nome { get; set; }

//public int CartaoCreditoID { get; set; } public virtual IList CartaoCredito { get; set; } }

2) Executei o comando:

PM> add-migration alteraBandeiraCartaoCredito -Context EntidadesContext An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy. To undo this action, use Remove-Migration.

3) Mas ao executar o:

PM> update-database -Context EntidadesContext

Obtive o resultado:

Applying migration '20170302020806_alteraBandeiraCartaoCredito'. System.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN KEY constraint 'FK_VendaCartaoCredito_Venda_VendaID' on table 'VendaCartaoCredito' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.<>c.<ExecuteNonQuery>b__13_0(DbCommand cmd, IRelationalConnection con) at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.Execute[T](IRelationalConnection connection, Func3 action, String executeMethod, Boolean openConnection, Boolean closeConnection) at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, Boolean manageConnection) at Microsoft.Data.Entity.Storage.RelationalCommandExtensions.ExecuteNonQuery(IEnumerable1 commands, IRelationalConnection connection) at Microsoft.Data.Entity.Migrations.Internal.Migrator.Execute(IEnumerable1 relationalCommands) at Microsoft.Data.Entity.Migrations.Internal.Migrator.Migrate(String targetMigration) at Microsoft.Data.Entity.Design.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType) at Microsoft.Data.Entity.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String contextType) at Microsoft.Data.Entity.Design.OperationExecutor.UpdateDatabase.<>cDisplayClass0_1.<.ctor>b0() at Microsoft.Data.Entity.Design.OperationExecutor.OperationBase.Execute(Action action) ClientConnectionId:d1ad8b70-86d5-4c95-8a74-63564a3c8441 Error Number:1785,State:0,Class:16

-- Essas últimas linhas estão em vermelho -- Introducing FOREIGN KEY constraint 'FK_VendaCartaoCredito_Venda_VendaID' on table 'VendaCartaoCredito' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors. -- Essas últimas linhas estão em vermelho --

4) Executei o mesmo tipo de alteração que havia feito em Vendas (alterei o onDelete para onUpdate).

migrationBuilder.AddForeignKey( name: "FK_VendaCartaoCredito_Venda_VendaID", table: "VendaCartaoCredito", column: "VendaID", principalTable: "Venda", principalColumn: "ID", //onDelete: ReferentialAction.Cascade); onUpdate: ReferentialAction.Cascade);

5) Executei o comando e deu tudo certo (graças a Deus!!!)

PM> update-database -Context EntidadesContext Applying migration '20170302020806_alteraBandeiraCartaoCredito'. Done. PM>

Agora, fiz o teste da venda com dois cartões de créditos:

// Teste da minha implementação do Cartão de Crédito

EntidadesContext contexto = new EntidadesContext();

UsuarioDAO dao = new UsuarioDAO();

Usuario freedy = dao.BuscaPorId(6);

Venda vendas = new Venda() { Cliente = freedy };

contexto.Vendas.Add(vendas);

Produto p = contexto.Produtos.FirstOrDefault(prod => prod.ID == 1); Produto p2 = contexto.Produtos.FirstOrDefault(prod => prod.ID == 2);

ProdutoVenda pv = new ProdutoVenda() { Produtos = p, VendaID = vendas.ID };

contexto.ProdutoVenda.Add(pv);

ProdutoVenda pv2 = new ProdutoVenda() { Produtos = p2, VendaID = vendas.ID };

contexto.ProdutoVenda.Add(pv2);

BandeiraCartaoCredito b = new BandeiraCartaoCredito() { Nome = "Credicar" };

contexto.Bandeiras.Add(b);

BandeiraCartaoCredito b2 = new BandeiraCartaoCredito() { Nome = "Visa" };

contexto.Bandeiras.Add(b2);

CartaoCredito c = new CartaoCredito() { BandeiraID = b.ID, Nome = "Freedy Carvalho", ClienteID = freedy.Id, Numero = "123456789000", MesValidade = 12, AnoValidade = 2023, CodVerificacao = 165 };

contexto.CartaoCredito.Add(c);

CartaoCredito c2 = new CartaoCredito() { BandeiraID = b2.ID, Nome = "Freedy Carvalho", ClienteID = freedy.Id, Numero = "000100020003", MesValidade = 01, AnoValidade = 2025, CodVerificacao = 132 };

contexto.CartaoCredito.Add(c2);

VendaCartaoCredito vc = new VendaCartaoCredito() { CartaoCreditoID = c.ID, VendaID = vendas.ID };

contexto.VendaCartaoCreditos.Add(vc);

VendaCartaoCredito vc2 = new VendaCartaoCredito() { CartaoCreditoID = c2.ID, VendaID = vendas.ID };

contexto.VendaCartaoCreditos.Add(vc2);

contexto.SaveChanges();

Verifiquei nas tabelas e todos os dados foram incluídos com sucesso, mas as minhas dúvidas são:

1) Foi uma implementação adequada? Poderia ter feito algo melhor?

2) Na tabela Venda, temos somente o campo ID e ClienteID. Mas não sei se essa venda foi paga com dinheiro ou cartão de crédito. Não seria interessante colocar um campo de forma de pagamento para evitar joins? O que sugere nesse caso? Crio a classe FormaPagamentoVenda?

Ainda não fiz o resgate das informações. Mas farei amanhã e gostaria de contar com a sua opinião.

Obrigado pela atenção.

Olá Freedy,

Quanto ao problema do contexto, vou passar para a galera do conteúdo da alura que talvez realmente esteja precisando dar uma atualizada no curso.

Quanto sua implementação,note que o VendaCartaoCredito serve apenas para ser a tabela do relacionamento entre a classe CartaoCredito e a classe Venda, que possuem um relacionamento Many to Many. E o mais interessante é que dentro de VendaCartaoCredito não existe nenhuma outra informação que não a do relacionamento entre estas entidades. Para evitar de ter que fazer esta tabela na mão, você poderia se aproveitar do Entity que já sabe fazer relacionamentos Many to Many. Nesta aula é apresentado como fazer este relacionamento só que entre as classes Venda e Produto, que seria similar ao seu CartaoCredito e Venda.

Quanto a saber se o pagamento foi feito em cartao ou dinheiro, no caso você já tem uma classe CartaoCredito. O jeito mais elegante de se fazer é criar uma classe Dinheiro com as informações específicas deste pagamento. E para relacionar com a Venda, o melhor jeito seria criar uma classe ou interface chamada de FormaDePagamento que tanto CartaoCredito quanto Dinheiro herdam. Ai na classe Venda você faz o relacionamento com a FormaDePagamento, se aproveitando do polimorfismo para que a Venda aceite estas duas formas. Ai se um dia quiser acrescentar alguma outra forma de pagamento, como cartao de debito, é só criar uma nova classe que herda de FormaDePagamento. Aqui tem um artigo bem legal sobre como fazer herança e polimorfismo com o Entity Framework.

Outra coisa só pra fechar, quando for mandar código você pode usar o botão de Inserir Código que tem na parte de cima dos formulários da Alura. Ele ajuda a formatar os textos de código e facilita a leitura de quem for te ajudar no fórum da Alura. Note que você mandou bastante código e não fica tão fácil de ler o que foi enviado dado que ele não foi formatado bonitinho.

Obrigado pela orientação. Vou fazer isso que orientou. Caso tenha mais alguma dúvida sobre esse assunto, posso criar outro tópico? Mais uma vez, obrigado.

Abs!

solução!

Ah, e vou usar o botão "inserir código", rs...

Sim, se tiver outros problemas com a modelagem é só criar um tópico novo no fórum. Bons estudos.