简体   繁体   中英

How to create relationship between entities & ApplicationUser in MVC 5 EF

If I have a SharedDocument entity with two properties I want to be related to my ApplicationUser entity, how do I do this?

On this MS Tutorial , see if you name the property the same as the PK of the table you want to relate EF can find the relationship pretty easily. But I have two properties, CreatedBy & ModifiedBy that I want related to my User table but I do not want to name them AspNetUserId . How can I do this?

Model

 public class SharedDocumentModel : DbContext
 {        
    public SharedDocumentModel()
        : base("MyContext")
    {

    }        

    public virtual DbSet<SharedDocument> PortalDocuments { get; set; }
 }

 public class SharedDocument
 {
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Created { get; set; }
    public virtual ApplicationUser CreatedBy { get; set; }
    public DateTime Modified { get; set; }
    public virtual ApplicationUser ModifiedBy { get; set; }
    public string ContentType { get; set; }
    public string FileType { get; set; }
    public byte[] FileContent { get; set; }
    public double Version { get; set; }
 }
}

Error on creating View with Model SharedDocuments

There was an error running the selected code generator: 
'Unable to retrieve metadata for 
'MVC.WebSite.Models.SharedDocument'. One or more validation 
errors 'mere detected during model generation: 
MVC.WebSite.DAL.IdentityUserLogin: EntityType 'IdentityUserLogin' 
has no key defined. Define the key for this EntityType. 
MVC.WebSite.DAL.IdentityUserRoIe: EntityType 'IdentityUserRoIe' has 
no key defined. Define the key for this EntityType. 
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based 
on Vpe 'IdentityUserLogin' that has no keys defined. 
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on 
type 'IdentityUserRole' that has no keys defined. 

You can do that by adding ForeignKey :

[ForeignKey("CreatedById")]
[ForeignKey("ModifiedById")]

So in you case:

public class SharedDocument
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Created { get; set; }
    [ForeignKey("CreatedById")]
    public virtual ApplicationUser CreatedBy { get; set; }
    public string CreatedById { get; set; }
    public DateTime Modified { get; set; }
    [ForeignKey("ModifiedById")]
    public virtual ApplicationUser ModifiedBy { get; set; }
    public string ModifiedById { get; set; }
    public string ContentType { get; set; }
    public string FileType { get; set; }
    public byte[] FileContent { get; set; }
    public double Version { get; set; }
}

One more thing: Merge your DbContext with ApplicationDbContext and use one database:

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

public class SharedDocumentModel : IdentityDbContext<ApplicationUser>
{
    public SharedDocumentModel()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }
    public virtual DbSet<SharedDocument> PortalDocuments { get; set; }
    public static SharedDocumentModel Create()
    {
        return new SharedDocumentModel();
    }
}

Your error message may be related to referencing ApplicationUser because it is in the IdentityDbContext<ApplicationUser> context. You can either setup your app context to inherit from the IdentityDbContext<ApplicationUser> , otherwise you will need to setup a copy of DbSet<ApplicationUser> in your SharedDocumentModel context.

You must match name of FK with property name not property type. So if you have a property with type User and name CreatedBy your FK property must CreatedByID not UserID . Therefore you could simply Add following 2 properties to your SharedDocument class.

public class SharedDocument
{
    public string CreatedByID { get; set; }
    public virtual ApplicationUser CreatedBy { get; set; }

    public string ModifiedByID { get; set; }
    public virtual ApplicationUser ModifiedBy { get; set; }
    // rest of your code
}

As you can see the type of FK properties are string since type of ApplicationUser 's PK is string also.

But another important issue, it seems you are using Identity's default configuration. If so you already have a DbContext on your project named ApplicationDbContext . Find it and add your other Entities to it. Don't implement new DbContext .

// This class already added to your project
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    // This context already had ApplicationUser set you don't need to add it again
    // add your own new entities 
    public DbSet<SharedDocument> PortalDocuments { get; set; }

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

At the end keep in mind to configuring EF you have 3 option:

1) Configuration by conventions, as I have done above.

2) Configuration by Data Annotation. By Adding Attribute to Properties or clasees:

[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }

3) Or by fluent API:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<SharedDocument>()
            .HasRequired(e => e.CreatedBy)
            .WithMany()
            .Map(e => e.MapKey("CreatedByID"));

        modelBuilder.Entity<SharedDocument>()
            .HasRequired(e => e.ModifiedBy)
            .WithMany()
            .Map(e => e.MapKey("ModifiedByID"));
    }
    // rest of code same as before
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM