Pracuję z Entity Framework Code First i MVC 5. Kiedy utworzyłem aplikację z uwierzytelnianiem indywidualnych kont użytkowników , otrzymałem kontroler konta, a wraz z nim wszystkie wymagane klasy i kod, który jest potrzebny do uruchomienia uwierzytelnienia kont użytkowników Indiv .
Wśród już wprowadzonego kodu był następujący:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DXContext", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Ale potem poszedłem do przodu i najpierw utworzyłem własny kontekst, używając kodu, więc mam teraz również:
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; }
}
Na koniec mam następującą metodę zarodka, aby dodać trochę danych do pracy podczas tworzenia:
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);
}
}
}
}
Moje rozwiązanie działa dobrze, ale kiedy próbuję uzyskać dostęp do kontrolera, który wymaga dostępu do bazy danych, pojawia się następujący błąd:
DX.DOMAIN.Context.IdentityUserLogin:: EntityType „IdentityUserLogin” nie ma zdefiniowanego klucza. Zdefiniuj klucz dla tego EntityType.
DX.DOMAIN.Context.IdentityUserRole:: EntityType „IdentityUserRole” nie ma zdefiniowanego klucza. Zdefiniuj klucz dla tego EntityType.
Co ja robię źle? Czy to dlatego, że mam dwa konteksty?
AKTUALIZACJA
Po przeczytaniu odpowiedzi Augusto wybrałem opcję 3 . Oto jak wygląda teraz moja klasa DXContext:
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();
}
}
Dodałem też a User.cs
i Role.cs
klasę, wyglądają tak:
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; }
}
Nie byłem pewien, czy będę potrzebować właściwości hasła na użytkowniku, ponieważ domyślny ApplicationUser ma to i kilka innych pól!
W każdym razie powyższa zmiana kompiluje się dobrze, ale ponownie pojawia się ten błąd, gdy aplikacja jest uruchomiona:
Nieprawidłowa nazwa kolumny UserId
UserId
jest własnością całkowitą na my Artist.cs
AddOrUpdate(new EntityObject { shoes = green})
również znanego jako „upsert”. w przeciwieństwie do zwykłego dodawania do kontekstu, w przeciwnym razie będziesz po prostu tworzyć zduplikowane / nadmiarowe informacje o kontekście encji.W moim przypadku poprawnie odziedziczyłem po IdentityDbContext (z własnymi niestandardowymi typami i zdefiniowanymi kluczami), ale nieumyślnie usunąłem wywołanie OnModelCreating klasy bazowej:
Który następnie naprawił moje brakujące indeksy z klas tożsamości, a następnie mogłem wygenerować migracje i odpowiednio włączyć migracje.
źródło
Dla tych, którzy używają ASP.NET Identity 2.1 i zmienili klucz podstawowy z domyślnego
string
na alboint
lubGuid
, jeśli nadal otrzymujeszprawdopodobnie zapomniałeś podać nowego typu klucza na
IdentityDbContext
:Jeśli tylko masz
lub nawet
podczas próby dodania migracji lub aktualizacji bazy danych pojawi się błąd „brak zdefiniowanego klucza”.
źródło
Zmieniając DbContext, jak poniżej;
Wystarczy dodać
OnModelCreating
wywołanie metody do base.OnModelCreating (modelBuilder); i będzie dobrze. Używam EF6.Specjalne podziękowania dla #The Senator
źródło
źródło
Mój problem był podobny - miałem nową tabelę, którą tworzyłem, ahd w celu powiązania z użytkownikami tożsamości. Po przeczytaniu powyższych odpowiedzi zdałem sobie sprawę, że ma to związek z IsdentityUser i odziedziczonymi właściwościami. Miałem już skonfigurowaną tożsamość jako własny kontekst, więc aby uniknąć nieodłącznego wiązania obu razem, zamiast używania powiązanej tabeli użytkownika jako prawdziwej właściwości EF, skonfigurowałem niepamapowaną właściwość z zapytaniem, aby uzyskać powiązane jednostki. (DataManager jest skonfigurowany do pobierania bieżącego kontekstu, w którym istnieje OtherEntity).
źródło