Using EF to store changes in database - entity-framework

I have an application (dotnet core 1.1, C#) with 5 main entities, each stored in it's own table. I would like to have one master table who persists all the changes with the following columns:
UserId (who made the change)
DateModified
Entity (which entity was changed)
EntityId (id of the entity changed)
NewValue
OldValue
What is the best approach for this problem? Doing this all manually seems like an aweful lot of work.

Different ways you can achieve this . you can create logging framework using NLog or Serilog libraries.
Since you have very few entities my opinion is to create an ActionFilter and use that to log the details into the master table.
public class LogAttribute : IActionFilter
{
public LogAttribute()
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
public void OnActionExecuted(ActionExecutedContext context)
{
// save details to master table
}
}

Related

How to Customize Migration History Table with Entity Framework Core

I'm setting up Entity Framework Core in a new API to deploy to an existing SQL Server database that is used by Entity Framework 4.6 applications. There is one Migration History table that is shared by other applications, and has 2 fields in it that need to be populated for each entry: ContextKey, and Model. Entity Framework Core does not have a Context Key, and does not save the Model to the Migration History table.
I've already created a HistoryRepository : SqlServerHistoryRepository and configured Entity Framework Core to use it, but the ConfigureTable method only allows you to create additional columns, but not actually populate each record as it gets inserted with custom data. Providing a default value to the column is not a solution.
public class HistoryRepository : SqlServerHistoryRepository
{
public HistoryRepository(HistoryRepositoryDependencies dependencies)
: base(dependencies)
{
}
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
{
base.ConfigureTable(history);
history.Property<string>("ContextKey")
.HasMaxLength(300);
history.Property<byte[]>("Model");
}
}
services.AddDbContext<MDSContext>(options =>
options.UseLazyLoadingProxies()
.UseSqlServer(
connectionString,
x => x.MigrationsHistoryTable("__MigrationHistory")).ReplaceService<Microsoft.EntityFrameworkCore.Migrations.IHistoryRepository, Burkhart.CoreServices.IncomingOrders.Core.Models.Base.HistoryRepository>()
);
I should be able to provide a custom value for ContextKey and Model dynamically
I looked all over for solutions, but they all show you how to add a column and set a default value, but not how to set a value dynamically. I ended up digging into the ASP.NET Entity Framework Core source code at GitHub for the solution, so that I would share it with everyone else, as I know there are others that are looking for this information:
Just override the GetInsertScript method on the HistoryRepository and insert your custom values. Here is the full solution:
public class HistoryRepository : SqlServerHistoryRepository
{
public HistoryRepository(HistoryRepositoryDependencies dependencies)
: base(dependencies)
{
}
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
{
base.ConfigureTable(history);
history.Property<string>("ContextKey")
.HasMaxLength(300);
history.Property<byte[]>("Model");
}
public override string GetInsertScript(HistoryRow row)
{
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
return new StringBuilder().Append("INSERT INTO ")
.Append(SqlGenerationHelper.DelimitIdentifier(TableName, TableSchema))
.Append(" (")
.Append(SqlGenerationHelper.DelimitIdentifier(MigrationIdColumnName))
.Append(", ")
.Append(SqlGenerationHelper.DelimitIdentifier(ProductVersionColumnName))
.Append(", [ContextKey], [Model])")
.Append("VALUES (")
.Append(stringTypeMapping.GenerateSqlLiteral(row.MigrationId))
.Append(", ")
.Append(stringTypeMapping.GenerateSqlLiteral(row.ProductVersion))
.Append($", '{ContextConstants.ContextName}.{ContextConstants.ContextSchemaName}', 0x)")
.AppendLine(SqlGenerationHelper.StatementTerminator)
.ToString();
}
}
Here is a link to the source code on github:
https://github.com/aspnet/EntityFrameworkCore/blob/master/src/EFCore.Relational/Migrations/HistoryRepository.cs

Added Column to the Database is NOT getting retrieved in the View

I am doing a online ASP.net MVC5 course from udemy.I added a new column to my Table using EF migration.
Name Column Added
namespace Vidly.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class AddNameToMembershipTypes : DbMigration
{
public override void Up()
{
AddColumn("dbo.MembershipTypes","Name",c => c.String(nullable:false));
}
public override void Down()
{
DropColumn("dbo.MembershipTypes","Name");
}
}
}
Then I updated my database for this migration.
Screen Shot for Confirmation
Customer and MembershipTypes Tables have one-to-one relationship and I am able to retrieve MembershipTypes fields from the Customer Table.
The only problem is that The new column "Name" I just added to the MembershipTypes as I described at the very top is NOT getting retrieved from the View.
Following is The Visual confirmation(Although I tried to add Name but got error)
When I forcefully tried to access Name I got following
I am Not getting why I am Not being able to access Name Field as I have added some values too using migration and updated my database.
My feeling is that the link between Customer and MembershipTypes needs to be updated somehow but I donot know how?
The changes you have in your AddNameToMembershipTypes is only for updating your database schema. That will not automatically update your entity class. You still need to add the new property to your MemberShipType class.
public class MembershipType
{
public string Name { set;get;} // This one here
// Your existing properties here
public int DurationInMonths { set;get; }
}

Mapping Entity Framework Code First to dynamically named tables

I'm currently using EF5 in a project with a legacy database. The legacy application uses dynamically build tables (xxxx_year, yyyy_year) to store "year based data". I've been trying to find a way to dynamically map the ef entities (xxxx, yyyy, etc) to the tables, based on the year property value, but I always end up getting the "The model backing the context has changed since the database was created." error. Can anyone give me some ideas on how to accomplish this ?
I found some old blog posts talking about edm mapping, where we can separate mapping tables based on some property value (kind of horizontal partitioning), but I can't find any pointers on how to accomplish the same using code first.
Thanks, P
In your mapping configuration for each domain object, you can tell EF that the corresponding table name for an entity is different from the entity name itself.
If your class is called YyyyYear, it can point to a table called "2012_year" by specifying the name in its mapping file.
e.g.
// 1 entity class per db table
public class YyyyYear
{
public int Id { get; set; }
}
// 1 mapping file for entity
using System.Data.Entity.ModelConfiguration;
public class YyyyYearMap: EntityTypeConfiguration
{
public YyyyYearMap()
{
this.HasKey(t => t.Id);
this.ToTable("2012_year");
}
}
// your db context class (derives from DbContext)
using System.Data.Entity;
public class MyDbContext: DbContext
{
// 1 db set for every entity/table
public DbSet YyyyYears { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// 1 mapping file for every entity/table
modelBuilder.Configurations.Add(new YyyyYearMap());
}
}
I'm not sure if that's what you're looking for, but I have a blog post with step-by-step instructions, a working sample, and how to resolve common issues.
http://wakeupandcode.com/entity-framework-code-first-migrations/
Hope this helps!

Create an Updatable Model - Entity Framework

I just want to know if there's a way on how to create an Updatable model. Right now, I have to create procedures for insert, update, and delete for all of the tables in my model. This is very tedious so I was wondering if there is one way which I could do to resolve this?
I remember before in my previous work that we used to make models and access them (CRUD) without creating procedures. But i'm not really certain now on how it was made.
Thank you!
There are various ways in which you can automate the generation (on the fly or already generated at compile time) of the actual SQL calls to the database to insert, select, update and delete within the Entity Framework.
You can use the ORM tools (e.g. Linq to Entities) to minimise or eliminate the writing of raw SQL. This means you still have to use the correct attributes on your entities and the properties/methods therein and that's a manual process. (Some backgrounding on this MSDN page)
You can allow the framework to automatically generate your entities based on some existing database schema (only possible with SqlServer-type databases) which basically does 90% of the work for you. There may be some cases where you need to override, for example, the default insert SQL with something custom. This is achieved via the Generate Database Wizard (which I think is a part of Visual Studio 2008+).
You can use POCO classes with EF. If you're using 4.1 and above, you can use the DbContext class. To map your model to the table / columns, simply override OnModelCreating in your context class (which inherits from DbContext). Say you have a model called User, a table called Users, and the context class MyContext, the code could be smth like this:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
}
public class MyContext : DbContext
{
public MyContext() :
base("MyContext")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().
.ToTable("Users");
modelBuilder.Entity<User>().
.Property(d => d.UserId)
.HasColumnName("UserId")
modelBuilder.Entity<User>().
.Property(d => d.UserName)
.HasColumnName("UserName");
}
}
To use it, simply add the User instance to your DbSet, then call SaveChanges:
using(MyContext ctx = new MyContext())
{
var u = new User() { UserId = 1, UserName = "A" };
ctx.Users.Add(u);
ctx.SaveChanges();
}

Entity Framework Code First - No Detach() method on DbContext

I'm wondering why there is no Detach method on the DbContext object like there is for ObjectContext.  I can only assume this omission was intentional, but I have a hard time figuring out why.  I need to be able to detach and re-attach entities (for putting in the cache in an ASP.NET project, for example).  However, since I can't detach an entity, when I try to attach an entity that was associated with a previous context, I get the "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" exception.
What's the guidance here?  Am I missing something?
For people that might stumble upon this question, as of CTP5 you now need to write
((IObjectContextAdapter)context).ObjectContext
in order to get to ObjectContext.
DbContext uses an ObjectContext internally and EF team make this available as a protected property just in case you ever need to drop down to the lower level API and sounds like this is the case here, so you can use or expose the required functionality from a derived DbContext:
public class YourContext : DbContext
{
public void Detach(object entity)
{
ObjectContext.Detach(entity);
}
}
Then you can call this method from your controller to detach an entity.
Alternatively, you can change it to even have a richer API:
public class YourContext : DbContext
{
public void ChangeObjectState(object entity, EntityState entityState)
{
ObjectContext.ObjectStateManager.ChangeObjectState(entity, entityState);
}
}
Here is how DbContext looks like from metadata:
public class DbContext : IDisposable
{
protected System.Data.Objects.ObjectContext ObjectContext { get; }
...
}
EF:CF 4.1 RC1 and EF:CF 4.1 RTW have the same explicitly implemented IObjectContextAdapter:
public static class DbContextExtensions
{
public static void Detach(this System.Data.Entity.DbContext context, object entity)
{
((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext.Detach(entity);
}
}
Microsoft decided "Detach is too advanced technology and should be hidden". IMHO the man who invented this should be shot - because if you add brand new entity, it is otherwise difficult to just remove it without commiting changes to db (you can manipulate with DbEntityEntry but that's another story).
Edit 4 years later:
With EF6 (i somehow skipped EF5 :) ) you dont need detach() anymore, becouse removing freshly added entry does not generate delete from [table] where [Id] = 0 as in EF4 - you can just call mySet.Remove(myFreshlyCreatedAndAddedEntity) and everything will be allright.
I usually extend the base class(inherits from the DbContext) with the property:
public class MyDbContext : DbContext
{
public ObjectContext ThisObjectContext
{
get
{
return ((IObjectContextAdapter)this).ObjectContext;
}
}
}
later you can use this property for variety of useful stuff ... like Detach :)