0

I am using the latest MVC6 and Entity Framework 7, however I am sure many techniques used in MVC5 and Entity Framework 6 could help answer my question also.

Almost all of the tables in my database have the following 4 fields for auditing: CreatedDate, CreatedBy, ModifiedDate, ModifiedBy.

I am trying to figure out which field from the built in IdentityUser (AspNetUsers table) I should be storing in the CreatedBy field when saving items to the database.

I started by trying to use 'Username' since it is easily accessible by calling User.Identity.Name and passing it down to the repository when saving. Here is how I configured EF using Fluent API to help with retrieving the User who created an item along with all of their fields:

builder.Entity<BlogPost>()
    .Property(bp => bp.CreatedBy)
    .HasMaxLength(256);

builder.Entity<BlogPost>()
    .HasOne(bp => bp.CreatedByUser)
    .WithMany()
    .HasForeignKey(bp => bp.CreatedBy)
    .HasPrincipalKey(u => u.UserName);

But then I noticed that Entity Framework yells when trying to add migrations and create the database because Username needs to be set as a primary key or it can't be used as a foreign key in another table.

Then I got to the point where I figured I would just use the actual Id which is a GUID. The problem with this technique is that the Id of the current logged in user isn't easily available when trying to save: 'User.Identity.Name' is all that is there.

Here are a couple of questions that I would like someone with EF and Auditing experience to try and answer for me:

  1. Do people even use Audit fields in all of their tables anymore? I don't see many others asking questions about this and Microsoft definitely doesn't make it easy to work with their new Identity system and custom audit fields.

  2. Should I be storing Username or Id in my CreatedBy field. Some say this might be preference but I really want to know what direction Microsoft might be pushing with the new Identity. The problem with storing Id is that it is hard to get it when saving and the problem with storing Username is that it isn't a primary key in AspNetUsers table.

  3. I really would just like to know of a good pattern in general when using EF that handles auditing when saving, and retrieving the User and setting it as a Navigation property on my entities that need it when pulling records from the database.

Blake Rivell
  • 10,899
  • 23
  • 93
  • 182

1 Answers1

1

I am trying to figure out which field from the built in IdentityUser (AspNetUsers table) I should be storing in the CreatedBy field when saving items to the database.

The user name of the person using the site (on Thread.CurrentPrincipal, accessed in ASP.Net via User.Identity.Name). Who else? That is the identity of the current authenticated user using your site, and it is what you should be putting in the audit tables.

Do people even use Audit fields in all of their tables anymore? I don't see many others asking questions about this and Microsoft definitely doesn't make it easy to work with their new Identity system and custom audit fields.

Yes, people do! All the time! If you are storing data that can be edited in any way by an end user (whether they are in your company or not), audit it. Always. I was going to say that all enterprises audit stuff to the extreme (and they do), but I even do that on my own personal projects. Metrics are extremely important!

And one important thing to remember is that just because people aren't asking about it on StackOverflow or some other site doesn't mean that it isn't prevalent and critical in our industry.

Should I be storing Username or Id in my CreatedBy field. Some say this might be preference but I really want to know what direction Microsoft might be pushing with the new Identity

Microsoft (and the team behind their Identity framework) are doing a great job with providing us a secure and robust security framework. Maybe they would recommend their approach to this problem, but their framework isn't really meant to address those nuances (which can and will differ from system to system). At the end of the day, pick whichever suits the schema of your database. I think most of the time that the Username would be appropriate to store (if it is unique within your system). After all, they both represent the same information (unless your usernames are not unique, which begs further questions).

I really would just like to know of a good pattern in general when using EF that handles auditing when saving, and retrieving the User and setting it as a navigation property on my entities that need it when pulling records from the database.

It is not, and most likely never will be EF's concern to help you with something like this. Sorry, that's just the way it is. Each application is unique, and EF (or any other ORM) can't be expected to meet everyone's needs.

I realize all of this doesn't really provide you with concrete answers, but I had to drop some advice.

rwisch45
  • 3,582
  • 2
  • 22
  • 35
  • Alright this answers half of what I needed to know. So your saying I should be using User.Identity.Name and saving the user's name in my CreatedBy fields. If I continue to do this am I on the right track with the settings I added using Fluent API? I guess what I am trying to do is tell EF that CreatedBy is a foreign key so when I try to retrieve the User as a Navigation property it can automatically populate all of the fields. – Blake Rivell Feb 29 '16 at 02:58
  • @Blake I haven't used EF with an enterprise application in a long time (I mainly use ORMs), so I couldn't answer that for you. But you don't have to have foreign keys between tables to do joins on them. And I really don't think this usage is approriate for a foreign key relationship. Just do a query that does an inner join on `MainUserIdentityTable.Username = AuditTable.Username`. I know for sure that EF allows for arbitrary SQL – rwisch45 Feb 29 '16 at 03:07
  • Do you use an ORM like Dapper? I am so close to going back to using it. It is so much easier to have control over how your entities get bound when retrieving data. Entity Framework tries to do so much mapping for you automatically that things start getting confusing. I was really trying to use code-first Entity Framework this time around with migrations and it hasn't been too smooth. – Blake Rivell Feb 29 '16 at 03:09
  • Yes, Dapper is what I use 99% of the time. I use EF a lot for protoype projects. It's easy for a lot of people to hate on EF, but as long as you don't forget what's really going on (SQL) then it can be a very useful tool. – rwisch45 Feb 29 '16 at 03:12
  • If I switch back to using Dapper it won't work with the built in ASP.NET Identity as easily will it? Since they give you the start Schema and try to get you to run migrations. – Blake Rivell Feb 29 '16 at 03:15
  • @BlakeRivell ASP.Net does not try to run any migrations. That is 100% EF. So yes, you could use Dapper (or any other micro ORM). Check out [this repo](https://github.com/whisperdancer/AspNet.Identity.Dapper) - it's targeted against EF6 and below, but the concepts still apply with EFCore and the new Identity framework – rwisch45 Feb 29 '16 at 03:18
  • I suppose this article might be able to help me also: http://blog.markjohnson.io/exorcising-entity-framework-from-asp-net-identity/ . I am aware that it is EF takes the model and runs migrations to create all of the AspNet tables. It just seems like it is really going to be a pain to use Identity with Dapper ORM. Do you use them both by any chance? – Blake Rivell Feb 29 '16 at 03:22
  • @BlakeRivell I have before, but the experience was no different than the other applications I worked on that had no ORM to manage their SQL schema and the countless changes it will inevitably need. On the surface, it definitely seems easier to use tooling (i.e EF) to manage your migrations; but I'd encourage you to try it yourself with Dapper. You'll come away with not only a better understanding of what's going on, but also a deeper appreciation for both EF (and tools like it) and *not* using tools like that. – rwisch45 Feb 29 '16 at 03:26
  • @BlakeRivell That may seem like vague advice. And it intentionally was. Because I know that I'd always use Dapper or another micro orm for any serious application I was working on. But I don't want you to take my word (or anyone else's) at face value on a Q&A site. Learning and experiencing it yourself is key. – rwisch45 Feb 29 '16 at 03:28
  • All of the advice is much appreciated. I have created custom User auth tables and have used Dapper in the past so I have an idea how a lot of it works. It is just frustrating that microsoft gives you ASP.NET Identity and pretty much only makes it work with EF out of the box and gives no documentation on how to make it work with other ORMS. – Blake Rivell Feb 29 '16 at 03:34
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/104821/discussion-between-blake-rivell-and-rwisch45). – Blake Rivell Feb 29 '16 at 03:46
  • Sorry did not mean to click to go into chat, but one approach that I did not think of was to leave ASP.NET Identity and EF in place and simply use dapper for everything else. – Blake Rivell Feb 29 '16 at 03:47