EntityType 'IdentityUserLogin' ไม่มีการกำหนดคีย์ กำหนดคีย์สำหรับ EntityType นี้


107

ฉันกำลังทำงานกับ Entity Framework Code First และ MVC 5 เมื่อฉันสร้างแอปพลิเคชันของฉันด้วยการตรวจสอบบัญชีผู้ใช้ส่วนบุคคลฉันได้รับตัวควบคุมบัญชีและคลาสและรหัสที่จำเป็นทั้งหมดที่จำเป็นในการรับการตรวจสอบสิทธิ์บัญชีผู้ใช้ Indiv เพื่อให้ทำงานได้ .

ในบรรดารหัสที่มีอยู่แล้วคือ:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext() : base("DXContext", throwIfV1Schema: false)
    {

    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

แต่จากนั้นฉันก็สร้างบริบทของตัวเองโดยใช้โค้ดก่อนดังนั้นตอนนี้ฉันก็มีสิ่งต่อไปนี้ด้วย:

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; }        
}

ในที่สุดฉันก็มีวิธีการเริ่มต้นต่อไปนี้เพื่อเพิ่มข้อมูลบางอย่างเพื่อให้ฉันใช้งานได้ในขณะที่พัฒนา:

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);
            }
        }
    }
    
}

โซลูชันของฉันทำงานได้ดี แต่เมื่อฉันลองและเข้าถึงคอนโทรลเลอร์ที่ต้องเข้าถึงฐานข้อมูลฉันได้รับข้อผิดพลาดต่อไปนี้:

DX.DOMAIN.Context.IdentityUserLogin:: EntityType 'IdentityUserLogin' ไม่มีการกำหนดคีย์ กำหนดคีย์สำหรับ EntityType นี้

DX.DOMAIN.Context.IdentityUserRole: EntityType 'IdentityUserRole' ไม่มีการกำหนดคีย์ กำหนดคีย์สำหรับ EntityType นี้

ผมทำอะไรผิดหรือเปล่า? เป็นเพราะฉันมีสองบริบท?

อัปเดต

หลังจากที่ได้อ่านตอบกลับออกัสของฉันไปกับตัวเลือกที่ 3 นี่คือลักษณะของคลาส 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();
    }
}

ฉันยังเพิ่ม a User.csและRole.csชั้นเรียนพวกเขามีลักษณะดังนี้:

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; }
}

ฉันไม่แน่ใจว่าฉันต้องการคุณสมบัติรหัสผ่านสำหรับผู้ใช้หรือไม่เนื่องจาก ApplicationUser เริ่มต้นมีฟิลด์นั้นและฟิลด์อื่น ๆ อีกมากมาย!

อย่างไรก็ตามการเปลี่ยนแปลงข้างต้นสร้างได้ดี แต่ฉันได้รับข้อผิดพลาดนี้อีกครั้งเมื่อเรียกใช้แอปพลิเคชัน:

ชื่อคอลัมน์ UserId ไม่ถูกต้อง

UserId เป็นคุณสมบัติจำนวนเต็มในไฟล์ Artist.cs

คำตอบ:


116

ปัญหาคือApplicationUserของคุณสืบทอดมาจาก IdentityUserซึ่งกำหนดไว้เช่นนี้:

IdentityUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser
....
public virtual ICollection<TRole> Roles { get; private set; }
public virtual ICollection<TClaim> Claims { get; private set; }
public virtual ICollection<TLogin> Logins { get; private set; }

และคีย์หลักของพวกเขาถูกแมปในเมธอดOnModelCreating ของคลาส IdentityDbContext :

modelBuilder.Entity<TUserRole>()
            .HasKey(r => new {r.UserId, r.RoleId})
            .ToTable("AspNetUserRoles");

modelBuilder.Entity<TUserLogin>()
            .HasKey(l => new {l.LoginProvider, l.ProviderKey, l.UserId})
            .ToTable("AspNetUserLogins");

และเนื่องจาก DXContext ของคุณไม่ได้มาจากมันคีย์เหล่านั้นจึงไม่ได้รับการกำหนด

ถ้าคุณขุดลงไปในแหล่งที่มาของMicrosoft.AspNet.Identity.EntityFrameworkคุณจะเข้าใจทุกอย่าง

ฉันเจอสถานการณ์นี้เมื่อไม่นานมานี้และฉันพบวิธีแก้ปัญหาที่เป็นไปได้สามวิธี (อาจมีมากกว่านั้น):

  1. ใช้ DbContexts แยกกับฐานข้อมูลที่ต่างกันสองฐานข้อมูลหรือฐานข้อมูลเดียวกัน แต่ต่างตาราง
  2. ผสาน DXContext ของคุณเข้ากับ ApplicationDbContext และใช้ฐานข้อมูลเดียว
  3. ใช้ DbContexts แยกกับตารางเดียวกันและจัดการการย้ายข้อมูลให้สอดคล้องกัน

ตัวเลือกที่ 1: ดูอัปเดตด้านล่าง

ตัวเลือกที่ 2: คุณจะได้ DbContext แบบนี้:

public class DXContext : IdentityDbContext<User, Role,
    int, UserLogin, UserRole, UserClaim>//: DbContext
{
    public DXContext()
        : base("name=DXContext")
    {
        Database.SetInitializer<DXContext>(null);// Remove default initializer
        Configuration.ProxyCreationEnabled = false;
        Configuration.LazyLoadingEnabled = false;
    }

    public static DXContext Create()
    {
        return new DXContext();
    }

    //Identity and Authorization
    public DbSet<UserLogin> UserLogins { get; set; }
    public DbSet<UserClaim> UserClaims { get; set; }
    public DbSet<UserRole> UserRoles { get; set; }
    
    // ... your custom DbSets
    public DbSet<RoleOperation> RoleOperations { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

        // Configure Asp Net Identity Tables
        modelBuilder.Entity<User>().ToTable("User");
        modelBuilder.Entity<User>().Property(u => u.PasswordHash).HasMaxLength(500);
        modelBuilder.Entity<User>().Property(u => u.Stamp).HasMaxLength(500);
        modelBuilder.Entity<User>().Property(u => u.PhoneNumber).HasMaxLength(50);

        modelBuilder.Entity<Role>().ToTable("Role");
        modelBuilder.Entity<UserRole>().ToTable("UserRole");
        modelBuilder.Entity<UserLogin>().ToTable("UserLogin");
        modelBuilder.Entity<UserClaim>().ToTable("UserClaim");
        modelBuilder.Entity<UserClaim>().Property(u => u.ClaimType).HasMaxLength(150);
        modelBuilder.Entity<UserClaim>().Property(u => u.ClaimValue).HasMaxLength(500);
    }
}

ทางเลือกที่ 3: คุณจะมี DbContext เท่ากับตัวเลือก 2 ตั้งชื่อมันว่า IdentityContext และคุณจะมี DbContext อื่นที่เรียกว่า DXContext:

public class DXContext : DbContext
{        
    public DXContext()
        : base("name=DXContext") // connection string in the application configuration file.
    {
        Database.SetInitializer<DXContext>(null); // Remove default initializer
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;
    }

    // Domain Model
    public DbSet<User> Users { get; set; }
    // ... other custom DbSets
    
    public static DXContext Create()
    {
        return new DXContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        // IMPORTANT: we are mapping the entity User to the same table as the entity ApplicationUser
        modelBuilder.Entity<User>().ToTable("User"); 
    }

    public DbQuery<T> Query<T>() where T : class
    {
        return Set<T>().AsNoTracking();
    }
}

ผู้ใช้อยู่ที่ไหน:

public class User
{
    public int Id { get; set; }

    [Required, StringLength(100)]
    public string Name { get; set; }

    [Required, StringLength(128)]
    public string SomeOtherColumn { get; set; }
}

ด้วยโซลูชันนี้ฉันกำลังแมปเอนทิตีผู้ใช้กับตารางเดียวกันกับเอนทิตี ApplicationUser

จากนั้นใช้รหัส Migrations แรกที่คุณจะต้องสร้างการโยกย้ายสำหรับ IdentityContext และแล้วสำหรับ DXContext ต่อไปโพสต์ที่ยอดเยี่ยมนี้จาก Shailendra ชัวฮาน: รหัสโยกย้ายครั้งแรกกับบริบทข้อมูลหลาย

คุณจะต้องแก้ไขการย้ายข้อมูลที่สร้างขึ้นสำหรับ DXContext สิ่งนี้ขึ้นอยู่กับคุณสมบัติที่ใช้ร่วมกันระหว่าง ApplicationUser และ User:

        //CreateTable(
        //    "dbo.User",
        //    c => new
        //        {
        //            Id = c.Int(nullable: false, identity: true),
        //            Name = c.String(nullable: false, maxLength: 100),
        //            SomeOtherColumn = c.String(nullable: false, maxLength: 128),
        //        })
        //    .PrimaryKey(t => t.Id);
        AddColumn("dbo.User", "SomeOtherColumn", c => c.String(nullable: false, maxLength: 128));

จากนั้นเรียกใช้การย้ายข้อมูลตามลำดับ (อันดับแรกคือการโอนย้ายข้อมูลประจำตัว) จาก global.asax หรือที่อื่น ๆ ของแอปพลิเคชันของคุณโดยใช้คลาสที่กำหนดเองนี้:

public static class DXDatabaseMigrator
{
    public static string ExecuteMigrations()
    {
        return string.Format("Identity migrations: {0}. DX migrations: {1}.", ExecuteIdentityMigrations(),
            ExecuteDXMigrations());
    }

    private static string ExecuteIdentityMigrations()
    {
        IdentityMigrationConfiguration configuration = new IdentityMigrationConfiguration();
        return RunMigrations(configuration);
    }

    private static string ExecuteDXMigrations()
    {
        DXMigrationConfiguration configuration = new DXMigrationConfiguration();
        return RunMigrations(configuration);
    }

    private static string RunMigrations(DbMigrationsConfiguration configuration)
    {
        List<string> pendingMigrations;
        try
        {
            DbMigrator migrator = new DbMigrator(configuration);
            pendingMigrations = migrator.GetPendingMigrations().ToList(); // Just to be able to log which migrations were executed

            if (pendingMigrations.Any())                
                    migrator.Update();     
        }
        catch (Exception e)
        {
            ExceptionManager.LogException(e);
            return e.Message;
        }
        return !pendingMigrations.Any() ? "None" : string.Join(", ", pendingMigrations);
    }
}

ด้วยวิธีนี้เอนทิตีการตัดข้าม n-tier ของฉันไม่ได้รับมรดกจากคลาส AspNetIdentity ดังนั้นฉันจึงไม่ต้องนำเข้าเฟรมเวิร์กนี้ในทุกโปรเจ็กต์ที่ฉันใช้

ขออภัยสำหรับการโพสต์ที่กว้างขวาง ฉันหวังว่ามันจะสามารถให้คำแนะนำเกี่ยวกับเรื่องนี้ได้ ฉันใช้ตัวเลือก 2 และ 3 ในสภาพแวดล้อมการผลิตแล้ว

อัปเดต: ขยายตัวเลือก 1

สำหรับสองโครงการล่าสุดฉันได้ใช้ตัวเลือกที่ 1: มีคลาส AspNetUser ที่มาจาก IdentityUser และคลาสกำหนดเองแยกต่างหากที่เรียกว่า AppUser ในกรณีของฉัน DbContexts คือ IdentityContext และ DomainContext ตามลำดับ และฉันกำหนด Id ของ AppUser ดังนี้:

public class AppUser : TrackableEntity
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    // This Id is equal to the Id in the AspNetUser table and it's manually set.
    public override int Id { get; set; }

(TrackableEntity เป็นคลาสพื้นฐานนามธรรมที่กำหนดเองที่ฉันใช้ในเมธอด SaveChanges ที่ถูกแทนที่ของบริบท DomainContext ของฉัน)

ฉันสร้าง AspNetUser ก่อนจากนั้นจึงสร้าง AppUser ข้อเสียเปรียบของวิธีนี้คือคุณต้องแน่ใจว่าฟังก์ชัน "CreateUser" ของคุณเป็นแบบธุรกรรม (โปรดจำไว้ว่าจะมี DbContexts สองตัวที่เรียกใช้ SaveChanges แยกกัน) การใช้ TransactionScope ไม่ได้ผลสำหรับฉันด้วยเหตุผลบางประการดังนั้นฉันจึงทำสิ่งที่น่าเกลียด แต่ก็เหมาะกับฉัน:

        IdentityResult identityResult = UserManager.Create(aspNetUser, model.Password);

        if (!identityResult.Succeeded)
            throw new TechnicalException("User creation didn't succeed", new LogObjectException(result));

        AppUser appUser;
        try
        {
            appUser = RegisterInAppUserTable(model, aspNetUser);
        }
        catch (Exception)
        {
            // Roll back
            UserManager.Delete(aspNetUser);
            throw;
        }

(กรุณาถ้ามีใครมาพร้อมกับวิธีที่ดีกว่าในการทำส่วนนี้ฉันขอขอบคุณที่แสดงความคิดเห็นหรือเสนอการแก้ไขคำตอบนี้)

ประโยชน์ที่ว่าคุณไม่ได้มีการปรับเปลี่ยนโยกย้ายและคุณสามารถใช้ลำดับชั้นมรดกบ้ามากกว่า AppUser โดยไม่ต้องไปยุ่งกับ AspNetUser และจริงๆแล้วฉันใช้ Automatic Migrations สำหรับ IdentityContext ของฉัน (บริบทที่มาจาก IdentityDbContext):

public sealed class IdentityMigrationConfiguration : DbMigrationsConfiguration<IdentityContext>
{
    public IdentityMigrationConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = false;
    }

    protected override void Seed(IdentityContext context)
    {
    }
}

วิธีนี้ยังมีประโยชน์ในการหลีกเลี่ยงที่จะมีเอนทิตีการตัดขวาง n-tier ของคุณที่สืบทอดมาจากคลาส AspNetIdentity


ขอบคุณ @Augusto สำหรับโพสต์ที่กว้างขวาง หนึ่งไม่ต้องใช้การโยกย้ายเพื่อให้ได้ตัวเลือกที่ 3 ในการทำงาน? เท่าที่ฉันทราบ EF Migrations มีไว้เพื่อย้อนการเปลี่ยนแปลงใช่หรือไม่ ถ้าฉันทิ้งฐานข้อมูลของฉันแล้วสร้างใหม่และเริ่มต้นใหม่ในแต่ละบิลด์ใหม่ฉันจำเป็นต้องทำการโยกย้ายทั้งหมดหรือไม่
J86

ฉันไม่ได้ลองโดยไม่ใช้การย้ายข้อมูล ฉันไม่รู้ว่าคุณสามารถทำได้โดยไม่ต้องใช้มัน อาจจะเป็นไปได้ ฉันต้องใช้การย้ายข้อมูลเพื่อเก็บข้อมูลที่กำหนดเองที่ถูกแทรกลงในฐานข้อมูลเสมอ
Augusto Barreto

สิ่งหนึ่งที่จะชี้ให้เห็นหากคุณใช้การโยกย้าย ... คุณควรใช้ความAddOrUpdate(new EntityObject { shoes = green})รู้อีกอย่างว่า ตรงข้ามกับการเพิ่มลงในบริบทมิฉะนั้นคุณจะสร้างข้อมูลบริบทเอนทิตีซ้ำ / ซ้ำซ้อน
Chef_Code

ฉันต้องการทำงานกับตัวเลือกที่ 3 แต่ฉันไม่เข้าใจ ใครช่วยบอกหน่อยได้ไหมว่า IdentityContext ควรมีลักษณะอย่างไร เพราะมันไม่เหมือนในตัวเลือกที่ 2! คุณช่วยฉัน @AugustoBarreto ได้ไหม? ฉันได้ตั้งกระทู้เกี่ยวกับสิ่งที่คล้ายกันบางทีคุณอาจช่วยฉันได้ที่นั่น
Arianit

'TrackableEntity' ของคุณมีลักษณะอย่างไร
Ciaran Gallagher

224

ในกรณีของฉันฉันได้รับช่วงจาก IdentityDbContext อย่างถูกต้อง (ด้วยประเภทที่กำหนดเองและกำหนดคีย์ของฉันเอง) แต่ได้ลบการเรียกไปยัง OnModelCreating ของคลาสพื้นฐานโดยไม่ได้ตั้งใจ:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder); // I had removed this
    /// Rest of on model creating here.
}

ซึ่งจะแก้ไขดัชนีที่ขาดหายไปของฉันจากคลาสเอกลักษณ์จากนั้นฉันสามารถสร้างการย้ายข้อมูลและเปิดใช้งานการย้ายข้อมูลได้อย่างเหมาะสม


มีปัญหาเดียวกัน "ลบบรรทัด". โซลูชันของคุณได้ผล :) ty.
พัฒนา Marius Žilėnas

2
สิ่งนี้แก้ไขปัญหาของฉันโดยที่ฉันต้องแทนที่เมธอด OnModelCreating เพื่อรวมการแมปแบบกำหนดเองโดยใช้ fluent api สำหรับความสัมพันธ์ของเอนทิตีที่ซับซ้อน ปรากฎว่าฉันลืมเพิ่มบรรทัดในคำตอบก่อนที่จะประกาศการแมปของฉันเนื่องจากฉันใช้บริบทเดียวกับ Identity ไชโย
แดน

ใช้งานได้ถ้าไม่มี 'override void OnModelCreating' แต่ถ้าคุณแทนที่คุณจะต้องเพิ่ม 'base OnModelCreating (modelBuilder);' ไปที่การแทนที่ แก้ไขปัญหาของฉัน
โจ

13

สำหรับผู้ที่ใช้ ASP.NET Identity 2.1 และได้เปลี่ยนคีย์หลักจากค่าเริ่มต้นstringเป็นอย่างใดอย่างหนึ่งintหรือGuidหากคุณยังคงได้รับ

EntityType 'xxxxUserLogin' ไม่มีการกำหนดคีย์ กำหนดคีย์สำหรับ EntityType นี้

EntityType 'xxxxUserRole' ไม่มีการกำหนดคีย์ กำหนดคีย์สำหรับ EntityType นี้

คุณอาจลืมระบุประเภทคีย์ใหม่บนIdentityDbContext:

public class AppIdentityDbContext : IdentityDbContext<
    AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>
{
    public AppIdentityDbContext()
        : base("MY_CONNECTION_STRING")
    {
    }
    ......
}

ถ้าคุณมี

public class AppIdentityDbContext : IdentityDbContext
{
    ......
}

หรือแม้กระทั่ง

public class AppIdentityDbContext : IdentityDbContext<AppUser>
{
    ......
}

คุณจะได้รับข้อผิดพลาด 'ไม่ระบุคีย์' เมื่อคุณพยายามเพิ่มการย้ายข้อมูลหรืออัปเดตฐานข้อมูล


ฉันกำลังพยายามเปลี่ยน ID เป็น Int และกำลังมีปัญหานี้ แต่ฉันได้เปลี่ยน DbContext เพื่อระบุประเภทคีย์ใหม่ มีที่อื่นอีกไหมที่ฉันควรตรวจสอบ ฉันคิดว่าฉันทำตามคำแนะนำอย่างระมัดระวัง
Kyle

1
@Kyle: คุณกำลังพยายามเปลี่ยน ID เอนทิตีทั้งหมดเป็น int เช่น AppRole, AppUser, AppUserClaim, AppUserLogin และ AppUserRole หรือไม่ ในกรณีนี้คุณอาจต้องตรวจสอบให้แน่ใจว่าคุณได้ระบุประเภทคีย์ใหม่สำหรับคลาสเหล่านั้นแล้ว เช่นเดียวกับ 'AppUserLogin ระดับสาธารณะ: IdentityUserLogin <int> {}'
David Liang

1
นี่คือเอกสารอย่างเป็นทางการเกี่ยวกับการปรับแต่งประเภทข้อมูลคีย์หลัก: docs.microsoft.com/en-us/aspnet/core/security/authentication/…
AdrienTorris

1
ใช่ปัญหาของฉันคือฉันได้รับมาจากคลาส DbContext ทั่วไปแทนที่จะเป็น IdentityDbContext <AppUser> ขอบคุณสิ่งนี้ช่วยได้มาก
yibe

13

โดยการเปลี่ยน DbContext ดังต่อไปนี้;

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
    }

เพียงแค่เพิ่มOnModelCreatingวิธีการโทรไปยัง base OnModelCreating (modelBuilder); และมันจะดี ฉันใช้ EF6

ขอขอบคุณเป็นพิเศษกับ # วุฒิสมาชิก


1
 protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            //foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
            //    relationship.DeleteBehavior = DeleteBehavior.Restrict;

            modelBuilder.Entity<User>().ToTable("Users");

            modelBuilder.Entity<IdentityRole<string>>().ToTable("Roles");
            modelBuilder.Entity<IdentityUserToken<string>>().ToTable("UserTokens");
            modelBuilder.Entity<IdentityUserClaim<string>>().ToTable("UserClaims");
            modelBuilder.Entity<IdentityUserLogin<string>>().ToTable("UserLogins");
            modelBuilder.Entity<IdentityRoleClaim<string>>().ToTable("RoleClaims");
            modelBuilder.Entity<IdentityUserRole<string>>().ToTable("UserRoles");

        }
    }

0

ปัญหาของฉันก็คล้ายกัน - ฉันมีตารางใหม่ที่ฉันกำลังสร้าง ahd นั้นเพื่อเชื่อมโยงกับผู้ใช้ข้อมูลประจำตัว หลังจากอ่านคำตอบข้างต้นแล้วตระหนักว่ามันเกี่ยวข้องกับ IsdentityUser และคุณสมบัติที่สืบทอดมา ฉันได้ตั้งค่า Identity เป็นบริบทของตัวเองแล้วดังนั้นเพื่อหลีกเลี่ยงการเชื่อมโยงทั้งสองเข้าด้วยกันโดยเนื้อแท้แทนที่จะใช้ตารางผู้ใช้ที่เกี่ยวข้องเป็นคุณสมบัติ EF ที่แท้จริงฉันจึงตั้งค่าคุณสมบัติที่ไม่ได้แมปกับแบบสอบถามเพื่อรับเอนทิตีที่เกี่ยวข้อง (DataManager ถูกตั้งค่าเพื่อดึงบริบทปัจจุบันที่มี OtherEntity อยู่)

    [Table("UserOtherEntity")]
        public partial class UserOtherEntity
        {
            public Guid UserOtherEntityId { get; set; }
            [Required]
            [StringLength(128)]
            public string UserId { get; set; }
            [Required]
            public Guid OtherEntityId { get; set; }
            public virtual OtherEntity OtherEntity { get; set; }
        }

    public partial class UserOtherEntity : DataManager
        {
            public static IEnumerable<OtherEntity> GetOtherEntitiesByUserId(string userId)
            {
                return Connect2Context.UserOtherEntities.Where(ue => ue.UserId == userId).Select(ue => ue.OtherEntity);
            }
        }

public partial class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }

        [NotMapped]
        public IEnumerable<OtherEntity> OtherEntities
        {
            get
            {
                return UserOtherEntities.GetOtherEntitiesByUserId(this.Id);
            }
        }
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.