0

Lets say I added a couple of additional properties to the default User when using asp.net identity:

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

I am aware that in my asp.net MVC controller I can simply do the following to get the current logged in user's name:

User.Identity.Name

So when saving to the database I can simply pass User.Identity.Name to my repository along with the object I am saving so the CreatedBy field can be populated.

Now lets say I am retrieving items from the database which have a field of CreatedBy that contains a string of the username, but I want to display Created by : FirstName + LastName in the View.

How do I obtain this extra information? If I was using pure SQL I would do an INNER JOIN on the AspNetUsers table where CreatedBy=Username and simply retrieve the FirstName and LastName in a custom column called CreatedByFullName.

Since I am using Entity Framework now along with the latest version of ASP.NET Identity I am a bit confused at how we are expected to retrieve user information to display in the View of our pages. Is it a matter of doing a join with linq in my repository or simply adding an object to each of my properties called ApplicationUser or is there better ways?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Blake Rivell
  • 13,105
  • 31
  • 115
  • 231
  • I think you might be looking for... [ASP MVC5 - Identity. How to get current ApplicationUser](http://stackoverflow.com/questions/20925822/asp-mvc5-identity-how-to-get-current-applicationuser). – Erik Philips Feb 28 '16 at 07:20
  • @ErikPhilips getting the current application user isn't what I need. I need a way of going from the CreatedBy field (which contains string username) in all of my objects to having all of the user who created the entity's information to display in the view. Kind of like how StackOverflow shows who each post in here is createdby – Blake Rivell Feb 28 '16 at 07:21
  • 1
    Did you create navigation properties on these objects (ones with CreatedBy) that *point to* the ApplicationUsers table? If so, a simple `.Include(x => x.CreatedByUser)` is all the code you'd need. – Erik Philips Feb 28 '16 at 07:23
  • @ErikPhilips That is what I was wondering if I should be doing. I kept using the term creating a complex object. So should I be added a property of type ApplicationUser to any object that I need this information? If I do so how can I populate that object with a linq query in my repository? – Blake Rivell Feb 28 '16 at 07:24
  • That is exactly what I needed to know. I would mark as correct answer if you posted it as an answer, but I guess since it turned out to be something so simple a comment is fine. – Blake Rivell Feb 28 '16 at 07:27
  • @ErikPhilips I am in the process of trying it now, but it just doesn't make sense to me how entity framework would know how to auto populate CreatedByUser without there being an actual foreign key connection. – Blake Rivell Feb 28 '16 at 07:32

2 Answers2

3

Assumptions:

  • You have a single tabled called ApplicationUser that contains all your users.
  • This table has an Id column(int) that you are reusing to store lookups in other tables.

Other classes (what I call uni-directional navigation properties):

public class BookContext : DbContext
{
    public DbSet<Book> Books { get; set; }
    public Dbset<ApplicationUser> Users { get; set; }

    public overridee OnModelCreating(DbModelBuilder modelBuilder)
    {
      modelBuilder.Entity<Book>()
        .HasRequired(b => b.CreatedByUser)
        .WithMany()
        .HasForeignKey(b => b.CreatedBy);
    }
}

public class Book
{
  public int CreatedBy { get; set; }
  public virtual ApplicationUser CreatedByUser { get; set; }
}

Then you'd simply

using (var bookContext = new BookContext())
{
  var firstBookWithRelatedUser bookContext.Books
    .Include(b => b.CreatedByUser)
    .First();
}

Something like that. I recommend reading the Entity Framework Documentation. Granted the above code I pretty much just wrote off the top of my head so I may not be exactly right.

If you wanted, what I call, Bi-Directional navigation properties:

public class ApplicationUser : IdentityUser
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public ICollection<Book> Books { get; set; }
}

then

    public overridee OnModelCreating(DbModelBuilder modelBuilder)
    {
      modelBuilder.Entity<Book>()
        .HasRequired(b => b.CreatedByUser)
        .WithMany(u => u.Books)
        .HasForeignKey(b => b.CreatedBy);
    }

Then you'd simply

using (var bookContext = new BookContext())
{
  var firstUserWithAllRelatedBooks = bookContext.Users
    .Include(u => u.Books)
    .First();
}

It really just depends on your needs. But becareful, you can end up with a Giant God DbContext that is aware of all relationships...

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • Ok so the trick was editing the modelBuilder in my DbConext. If you see my last comment above I was wondering how I would tell EF about this connection. – Blake Rivell Feb 28 '16 at 07:33
  • You can also use the [ForeignKeyAttribute](https://msdn.microsoft.com/en-us/data/jj591583.aspx), but I prefer not to add metadata to my Poco objects. – Erik Philips Feb 28 '16 at 07:35
  • I agree, got it! thanks! Did you pull that modelBuilder example from the documenation? If so I would like to know which part. What is the purpose of the WithMany() part? Figures I am using EF7 and there aren't any of those options. I will have to do some research and find equivalents. – Blake Rivell Feb 28 '16 at 07:35
  • If you have a sec I found this documentation that has a perfect example: http://ef.readthedocs.org/en/latest/modeling/relational/fk-constraints.html but in my case lets say I have an Object called Book with a property called CreatedByUser, but there is no connection the other way around meaning CreatedByUser does not have a List of books. What do I need from this example and what do I not need? – Blake Rivell Feb 28 '16 at 07:45
  • Depends, EF supports bi-directional and uni-directional navigation properties... I'll update my example. – Erik Philips Feb 28 '16 at 08:07
  • This is my best attempt: .HasOne(fp => fp.CreatedByUser).WithOne().HasForeignKey("CreatedBy"); – Blake Rivell Feb 28 '16 at 08:09
  • *What do I need from this example and what do I not need?* I don't know, what do you need? – Erik Philips Feb 28 '16 at 08:13
  • I apologize if I wasn't clear, but I was trying to tell you that I do not want bi-directional. I just want one way meaning the ApplicationUser knows nothing about the Book. The Book just needs a single object of ApplicationUser populated. – Blake Rivell Feb 28 '16 at 08:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/104769/discussion-between-erik-philips-and-blake-rivell). – Erik Philips Feb 28 '16 at 08:17
0

Sample EF query will look like below -

var result = (from tab in db.YourTable
            join user in db.AspNetUsers on user.username equals tab.CreatedBy                
            select new {YourTableObj = tab, CreatedByFullName = user.FirstName + " " + user.LastName).ToList();
Vinit
  • 2,540
  • 1
  • 15
  • 22
  • Do you think this is the way I should be doing it? Would I want to add a property of ApplicationUser to my object to make it complex? In most cases I just use Include to populate my complex objects but in this case I can't use include right? – Blake Rivell Feb 28 '16 at 07:19
  • I certainly would not do this, by passing the Identity framework is possible.. but why do it... – Erik Philips Feb 28 '16 at 07:20