Scaffold-DbContext - how to prevent it from adding few same columns such as ID, CreatedDate, CreatedBy, etc - .net-core

All tables have few same columns (ID, CreatedDate, CreatedBy). I want to use these columns in new BaseEntity.cs, then bind it to all entities. I don't have to remove these columns and bind BaseEntity.cs in one by one entity class after entering scaffold-dbcontext command. Is it possible to do that?
I do not want to get auto entity generated after using scaffold-dbcontext like this.
public partial class User
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? CreatedDate { get; set; }
public string CreatedBy { get; set; }
}
I need to get like this. Scaffold-DbContext without adding ID, CreatedDate, CreatedBy.
public partial class User
{
public string Name { get; set; }
}
Then I can use ID, CreatedDate and CreatedBy in BaseEntity.cs and bind it to all entities classes. I don't have to remove 3 columns manually from every entity classes after every scaffold-dbcontext command.
public class BaseEntity
{
public int Id { get; set; }
public DateTime? CreatedDate { get; set; }
public string CreatedBy { get; set; }
}
.
public partial class User : BaseEntity
{
public string Name { get; set; }
}

You can use base Dto class with CreatedBy, CreatedDate ... properties, and then override SaveChanges() method in your DbContext to make those changes on update and on create for every entity. Like this:
public override int SaveChanges()
{
if (_contextAuditor != null)
{
Update(ChangeTracker.Entries());
Create(ChangeTracker.Entries());
}
return base.SaveChanges();
}
public void Update(IEnumerable<EntityEntry> changedEntities)
{
IEnumerable<EntityEntry> editedEntities = changedEntities
.Where(e => e.State == EntityState.Modified)
.ToList();
foreach (EntityEntry entity in editedEntities)
{
if (entity.Entity is IUpdateableDtoModel updateableEntity)
{
updateableEntity.UpdatedDate = DateTime.Now;
updateableEntity.UpdatedBy = GetCurrentUserName();
}
}
}
public void Create(IEnumerable<EntityEntry> changedEntities)
{
IEnumerable<EntityEntry> createdEntities = changedEntities
.Where(e => e.State == EntityState.Added)
.ToList();
foreach (EntityEntry entity in createdEntities)
{
if (entity.Entity is ICreateableDtoModel updateableEntity)
{
updateableEntity.CreatedDate = DateTime.Now;
updateableEntity.CreatedBy = updateableEntity.CreatedBy ?? GetCurrentUserName();
}
}
}

Related

Entity Framework Core Join identity AspNetUser table. AspNetUser Id to custom tables/Entities

I started a new Blazor application and I am trying to use Entity FrameworkCore. I want to link the Identity AspNetUsers table. I want a 1-many relationship with an UserAddress Table. One AspNetUser has many addresses.
public class UserAddress
{
public string Id { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string ZipCode { get; set; }
' I don't know what to put here to connect this table with the AspNetUsers Table
public int UserId {get;set} This doesn't work
}
I don't know what to do to have EF construct the 1 to many relation between the AspNetUsers Id and the UserAddress table
You can create a one-to-many relationship like this.
UserAddress class:
public class UserAddress
{
public string Id { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string ZipCode { get; set; }
}
New ApplicationUser inherits Identityuser:
public class ApplicationUser:IdentityUser
{
public ICollection<UserAddress> UserAddresses { get; set; }
}
Make changes in your ApplicationDbContext as follows:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(b => { b.HasMany(p => p.UserAddresses); }) ;
}
public DbSet<UserAddress> UserAddresses { get; set; }
}
Then start the migration and update the database.
Result:

How can I initialize one model in another model's controller action?

I created a web-app in Asp.net MVC and it has an order action. I have these two models for Order
public class Order
{
public int Id { get; set; }
public DateTimeOffset OrderTime { get; set; }
[InverseProperty("Order")]
public ICollection<OrderDetail> OrderDetails { get; set; }
}
and for OrderDetail
public class OrderDetail
{
public int Id { get; set; }
public int OrderId { get; set; }
public ICollection<Order> Order { get; set; }
public int MenuId { get; set; }
public int RestaurantId { get; set; }
public Menu Menu { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
And I created tables for them.
Also I created a controller for Order. It contains Index and Details actions. Index acction shows the list of order and every order has its own Detail link which should contain information of Order and related OrderDetail
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Order order = db.Orders.Find(id);
if (order == null)
{
return HttpNotFound();
}
return View(order);
}
And the problem is that OrderDetails is null. Can you suggest me how I can initialize OrderDetail in Details action?
You have to tell EntityFramework which navigation properties you want to include.
Order order = db.Orders
.Where( o => o.Id == id )
.Include( o => o.OrderDetails )
.SingleOrDefault();
But you cannot use Find method any more

asp.net - LINQ Query with relational Data

I have two tables Category and Document. See relationships in picture
See picture
I wrote the following query to select data from both tables based on relationship
public List<DocumentViewModel> All()
{
var docs = _context.Document.ToList();
List<DocumentViewModel> docList = docs.Select(x => new DocumentViewModel
{ DocumentId = x.DocumentId,
DocumentPath = x.DocumentPath,
CategoryId = x.CategoryId,
CategoryName = x.Category.CategoryName }).ToList();
return docList;
}
when this function is called , I get the following error
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Here are my modals
document
public class Document
{
[Key]
public int DocumentId { get; set; }
[Required]
public string DocumentPath { get; set; }
public Nullable<int> CategoryId { get; set; }
public virtual Category Category { get; set; }
}
Category
public class Category
{
[Key]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
DocumentViewModel
public class DocumentViewModel
{
public int DocumentId { get; set; }
public string DocumentPath { get; set; }
public int? CategoryId { get; set; }
public string CategoryName { get; set; }
}
Any Idea where am doing mistake?
In this case there is no reason to get a List in memory and then do the projection, you can do this directly from EF instead. Even if there is no relationship defined EF will return null for CategoryName if you project the the results. If you go to memory first then an NRE is expected if there is no Category relationship.
public List<DocumentViewModel> All()
{
return _context.Document.Select(x => new DocumentViewModel
{ DocumentId = x.DocumentId,
DocumentPath = x.DocumentPath,
CategoryId = x.CategoryId,
CategoryName = x.Category.CategoryName}).ToList();
}
Original reason why it is failing.
There is at least one entity that does not have a corresponding relationship with Category.
You do not have lazy loading enabled (which is a good thing) and if that is the case you should use Include to return the relationship.

Created and Modified date issue

I was practicing User.Identity and timestamps functions in ASP.NET MVC 5,
So I created a student class filled some properties, I just wanted to test if it is capturing timestamps and userId, so user id is getting captured and datetime too, problem is whenever I'm editing a record and save it, its created date becomes Null and modified date is updated, please review the code and help.
Thanks in advance.
Below is the Code
{
public class BaseEntity
{
public DateTime? DateCreated { get; set; }
public string UserCreated { get; set; }
public DateTime? DateModified { get; set; }
public string UserModified { get; set; }
}
public class Student : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Subject { get; set; }
public string Class { get; set; }
public Section Section { get; set; }
public byte SectionId { get; set; }
}
then I used Codefirst approach and created an application Database and added this code in Identity Model
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Student> Students { get; set; }
public override int SaveChanges()
{
AddTimestamps();
return base.SaveChanges();
}
//public override async Task<int> SaveChangesAsync()
//{
// AddTimestamps();
// return await base.SaveChangesAsync();
//}
private void AddTimestamps()
{
var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));
var currentUsername = !string.IsNullOrEmpty(System.Web.HttpContext.Current?.User?.Identity?.Name)
? HttpContext.Current.User.Identity.Name
: "Anonymous";
foreach (var entity in entities)
{
if (entity.State == EntityState.Added)
{
((BaseEntity)entity.Entity).DateCreated = DateTime.UtcNow;
((BaseEntity)entity.Entity).UserCreated = currentUsername;
}
else
((BaseEntity)entity.Entity).DateModified = DateTime.UtcNow;
((BaseEntity)entity.Entity).UserModified = currentUsername;
}
}
public DbSet<Section> Sections { get; set; }
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I have created a simple controller with create,edit and dispay actions.
The code you posted doesn't show DateCreated being set to null as far as I can see. I think the issue is when you save an existing record you do not have the DateCreated or UserCreated fields in your view. So when you post the form the MVC model binder doesn't see them and thus sets them to null (I'm assuming your are binding to the Student model in your controller action).
In your edit view add the following hidden fields:
#Html.HiddenFor(model => model.DateCreated)
#Html.HiddenFor(model => model.UserCreated)
Now when you post the form the MVC model binder will bind these values to your model and save them to the database.

How to join my tables with identity tables?

I started a default MVC project with Identity and EF.
In my app users will be able to create and edit some records.
In the table for these records, I want to have the ids of users who created the record and who updated lastly.
My model class is like:
public class Record
{
public int ID { get; set; }
public DateTime CreateTime { get; set; }
public string CreatingUserID { get; set; }
public string UpdatingUserID { get; set; }
public DateTime UpdateTime { get; set; }
public Enums.RecordStatus Status { get; set; }
}
And in RecordsController, I save new records to db like this:
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(FormCollection form, RecordCreateVM vm)
{
string userId = User.Identity.GetUserId();
DateTime now = DateTime.Now;
Record rec = new Record ();
if (ModelState.IsValid)
{
int newRecordId;
using (RecordRepository wr = new RecordRepository())
{
UpdateModel(rec);
rec.CreateTime = now;
rec.UpdateTime = now;
rec.CreatingUserID = userId;
rec.UpdatingUserID = userId;
rec.Status = Enums.RecordStatus.Active;
Record result = wr.Add(rec);
wr.SaveChanges();
newRecordId = result.ID;
}
}
}
When I am listing these records, I also want my page to display these users' usernames.
I get all the active records from the repository I created.
public ActionResult Index()
{
RecordListVMviewModel = new RecordListVM();
using (RecordRepository wr = new (RecordRepository())
{
viewModel.Records = wr.GetAll();
}
return View(viewModel);
}
And this is the repository code:
public class RecordRepository: Repository<Record>
{
public override List<Record> GetAll()
{
IQueryable<Record> activeRecords = DbSet.Where(w => w.Status == Enums.RecordStatus.Active);
return activeRecords.ToList();
}
}
Where do I have to make changes? Can you give me an sample code for usages like this?
Thank you.
You need to change
public string CreatingUserID { get; set; }
public string UpdatingUserID { get; set; }
to something like:
public User CreatingUser { get; set; }
public User UpdatingUser { get; set; }
Set the ID's during the creation of new RecordRepository()
Then access them as Record.CreatingUser.FirstName ect

Resources