Estoy trabajando con Entity Framework Code First y MVC 5. Cuando creé mi aplicación con autenticación de cuentas de usuario individual, me dieron un controlador de cuenta y, junto con él, todas las clases y el código necesarios para que la autenticación de cuentas de usuario indiv funcione. .
Entre el código que ya estaba en vigor estaba este:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DXContext", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Pero luego seguí adelante y creé mi propio contexto usando código primero, así que ahora también tengo lo siguiente:
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, tengo el siguiente método de semilla para agregar algunos datos con los que trabajar mientras desarrollo:
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);
}
}
}
}
Mi solución se compila bien, pero cuando intento acceder a un controlador que requiere acceso a la base de datos, aparece el siguiente error:
DX.DOMAIN.Context.IdentityUserLogin:: EntityType 'IdentityUserLogin' no tiene una clave definida. Defina la clave para este EntityType.
DX.DOMAIN.Context.IdentityUserRole:: EntityType 'IdentityUserRole' no tiene una clave definida. Defina la clave para este EntityType.
¿Qué estoy haciendo mal? ¿Es porque tengo dos contextos?
ACTUALIZAR
Después de leer la respuesta de Augusto, opté por la opción 3 . Así es como se ve mi clase DXContext ahora:
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();
}
}
También agregué una User.cs
y una Role.cs
clase, se ven así:
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; }
}
No estaba seguro de si necesitaría una propiedad de contraseña en el usuario, ¡ya que el ApplicationUser predeterminado tiene eso y muchos otros campos!
De todos modos, el cambio anterior se construye bien, pero nuevamente aparece este error cuando se ejecuta la aplicación:
Nombre de columna no válido UserId
UserId
es una propiedad entera en mi Artist.cs
AddOrUpdate(new EntityObject { shoes = green})
también conocido como "upsert". en lugar de simplemente agregar al contexto, de lo contrario, solo creará información de contexto de entidad duplicada / redundante.En mi caso, había heredado de IdentityDbContext correctamente (con mis propios tipos personalizados y clave definida) pero sin darme cuenta eliminé la llamada al OnModelCreating de la clase base:
Lo que luego corrigió mis índices faltantes de las clases de identidad y luego pude generar migraciones y habilitar las migraciones de manera adecuada.
fuente
Para aquellos que usan ASP.NET Identity 2.1 y han cambiado la clave principal de la predeterminada
string
aint
oGuid
, si aún obtieneprobablemente olvidó especificar el nuevo tipo de clave en
IdentityDbContext
:Si solo tienes
o incluso
Obtendrá el error "sin clave definida" cuando intente agregar migraciones o actualizar la base de datos.
fuente
Cambiando el DbContext como se muestra a continuación;
Simplemente agregando la
OnModelCreating
llamada al método a base.OnModelCreating (modelBuilder); y se pone bien. Estoy usando EF6.Agradecimiento especial a #El Senador
fuente
fuente
Mi problema fue similar: tenía una nueva tabla que estaba creando para vincularla a los usuarios de identidad. Después de leer las respuestas anteriores, se dio cuenta de que tenía que ver con IsdentityUser y las propiedades heredadas. Ya tenía la identidad configurada como su propio contexto, por lo que para evitar unir inherentemente los dos, en lugar de usar la tabla de usuario relacionada como una verdadera propiedad EF, configuré una propiedad no mapeada con la consulta para obtener las entidades relacionadas. (DataManager está configurado para recuperar el contexto actual en el que existe OtherEntity).
fuente