Estou trabalhando com Entity Framework Code First e MVC 5. Quando criei meu aplicativo com autenticação de contas de usuário individual, recebi um controlador de conta e junto com ele todas as classes e códigos necessários para fazer a autenticação de contas de usuário Indiv funcionar .
Entre os códigos já implementados estava este:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DXContext", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Mas então eu fui em frente e criei meu próprio contexto usando o código primeiro, então agora tenho o seguinte também:
public class DXContext : DbContext
{
public DXContext() : base("DXContext")
{
}
public DbSet<ApplicationUser> Users { get; set; }
public DbSet<IdentityRole> Roles { get; set; }
public DbSet<Artist> Artists { get; set; }
public DbSet<Paintings> Paintings { get; set; }
}
Finalmente, tenho o seguinte método de semente para adicionar alguns dados para eu trabalhar durante o desenvolvimento:
protected override void Seed(DXContext context)
{
try
{
if (!context.Roles.Any(r => r.Name == "Admin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "Admin" };
manager.Create(role);
}
context.SaveChanges();
if (!context.Users.Any(u => u.UserName == "James"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { UserName = "James" };
manager.Create(user, "ChangeAsap1@");
manager.AddToRole(user.Id, "Admin");
}
context.SaveChanges();
string userId = "";
userId = context.Users.FirstOrDefault().Id;
var artists = new List<Artist>
{
new Artist { FName = "Salvador", LName = "Dali", ImgURL = "http://i62.tinypic.com/ss8txxn.jpg", UrlFriendly = "salvador-dali", Verified = true, ApplicationUserId = userId },
};
artists.ForEach(a => context.Artists.Add(a));
context.SaveChanges();
var paintings = new List<Painting>
{
new Painting { Title = "The Persistence of Memory", ImgUrl = "http://i62.tinypic.com/xx8tssn.jpg", ArtistId = 1, Verified = true, ApplicationUserId = userId }
};
paintings.ForEach(p => context.Paintings.Add(p));
context.SaveChanges();
}
catch (DbEntityValidationException ex)
{
foreach (var validationErrors in ex.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
}
Minha solução funciona bem, mas quando tento acessar um controlador que requer acesso ao banco de dados, recebo o seguinte erro:
DX.DOMAIN.Context.IdentityUserLogin:: EntityType 'IdentityUserLogin' não tem chave definida. Defina a chave para este EntityType.
DX.DOMAIN.Context.IdentityUserRole:: EntityType 'IdentityUserRole' não tem chave definida. Defina a chave para este EntityType.
O que estou fazendo de errado? É porque tenho dois contextos?
ATUALIZAR
Depois de ler a resposta de Augusto, escolhi a Opção 3 . Esta é a aparência da minha classe DXContext agora:
public class DXContext : DbContext
{
public DXContext() : base("DXContext")
{
// remove default initializer
Database.SetInitializer<DXContext>(null);
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
}
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<Artist> Artists { get; set; }
public DbSet<Painting> Paintings { get; set; }
public static DXContext Create()
{
return new DXContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<Role>().ToTable("Roles");
}
public DbQuery<T> Query<T>() where T : class
{
return Set<T>().AsNoTracking();
}
}
Eu também adicionei uma User.cs
e uma Role.cs
classe, elas se parecem com isto:
public class User
{
public int Id { get; set; }
public string FName { get; set; }
public string LName { get; set; }
}
public class Role
{
public int Id { set; get; }
public string Name { set; get; }
}
Eu não tinha certeza se precisaria de uma propriedade de senha para o usuário, já que o ApplicationUser padrão tem isso e vários outros campos!
De qualquer forma, a alteração acima funciona bem, mas novamente recebo este erro quando o aplicativo é executado:
Nome de coluna inválido UserId
UserId
é uma propriedade inteira no meu Artist.cs
AddOrUpdate(new EntityObject { shoes = green})
também conhecido como "upsert". em vez de apenas adicionar ao contexto, caso contrário, você estará apenas criando informações de contexto de entidade duplicadas / redundantes.No meu caso, eu herdei do IdentityDbContext corretamente (com meus próprios tipos personalizados e chave definidos), mas removi inadvertidamente a chamada para OnModelCreating da classe base:
O que então corrigiu meus índices ausentes das classes de identidade e eu poderia gerar migrações e habilitá-las de forma adequada.
fonte
Para aqueles que usam ASP.NET Identity 2.1 e mudaram a chave primária do padrão
string
paraint
ouGuid
, se você ainda estiver recebendovocê provavelmente apenas se esqueceu de especificar o novo tipo de chave em
IdentityDbContext
:Se você apenas tiver
ou mesmo
você obterá o erro 'nenhuma chave definida' quando tentar adicionar migrações ou atualizar o banco de dados.
fonte
Alterando o DbContext conforme abaixo;
Apenas adicionando a
OnModelCreating
chamada de método a base.OnModelCreating (modelBuilder); e fica bem. Estou usando EF6.Agradecimentos especiais a #O senador
fonte
fonte
Meu problema era semelhante - eu tinha uma nova tabela que estava criando para vincular aos usuários de identidade. Depois de ler as respostas acima, percebi que tinha a ver com IsdentityUser e as propriedades herdadas. Eu já tinha Identidade configurada como seu próprio Contexto, portanto, para evitar amarrar inerentemente os dois, em vez de usar a tabela de usuário relacionada como uma propriedade EF verdadeira, configurei uma propriedade não mapeada com a consulta para obter as entidades relacionadas. (DataManager é configurado para recuperar o contexto atual no qual OtherEntity existe.)
fonte