EF Code First Migration - Property migration - c#

So Imagine this situation:
namespace SC.BL.Domain
{
public class User
{
public String Name { get; set; }
public String Adress { get; set; }
public int PhoneNumber { get; set; }
public char Gender { get; set; }
}
}
EF Code first migration is enabled. I implemented code-based migration by using 'enable-migrations'
My DbInitializer is set to use the MigrateDatabaseToLatestVersion initializer
Now my question is, I would like to migrate one property into multiple properties, without the loss of data, after this the old property may be removed!
Suppose I have in my database the following,
Name: User1
Address: Emmalaan 2, Gelderland
PhoneNumber: 0471250950
Gender: M
Now I want to change my User class to the following:
namespace SC.BL.Domain
{
public class User
{
public String Name { get; set; }
public String StreetName { get; set; }
public int HouseNumber { get; set; }
public String City { get; set; }
public int PhoneNumber { get; set; }
public char Gender { get; set; }
}
}
So now I want that after migrations, the data in the database is changed (without dataloss) and put in the right properties.
Where can I till the migrator to do something like this?
Name: User1
StreetName: Emmalaan 2
HouseNumber: 2
City: Gelderland
PhoneNumber: 0471250950
Gender: M
Is this possible via migration? And how is this done?

I think that the only thing you could do is the editing of the generated migration to do the transformation you want.
Inside Up() method of the migration:
use the Sql() method to write the data into a temporary table
migrate the table to the new structure (with the generated code)
use the Sql() method to take all the data (splitted as you want) from the temporary table so you can fill the edited table
in the Down() method the inverse of Up().

I don't think that this is possible via migration. You want to change structure of table, and you want that migration automatically separate data in different columns. I think that this is not possible. I think that better way is to only add columns by migration and after that you can create SQL procedure for splitting and updating data to different columns.

Related

Executing stored procedure from Entity Framework 7

I'm having a procedure which simply returns data from multiple tables. I'm trying to execute this procedure from EF as follows
await _context.Database.SqlQuery<TEntity>(command).ToListAsync();
Firstly, I have created a model class with property names to match the columns returned by the SP. Removed some properties for simplification,
public partial class Inventory
{
public string? location { get; set; }
public string? Warehouse { get; set; }
public string? Company { get; set; }
public string? Item { get; set; }
}
secondly, Added DbSet property to the context class
public virtual DbSet<Inventory> Inventorys { get; set; }
Then, I'm trying to call MapToStoredProcedures on entity Inventory.
modelBuilder.Entity<Inventory>().MapToStoredProcedures();
But, MapToStoredProcedures() is not recognized. I've verified that EF 7 packages are referenced by the project. What Am I missing here?
I followed the steps in https://erikej.github.io/efcore/2020/08/03/ef-core-call-stored-procedures-out-parameters.html and was able to get it working.

Cannot migrate new table in asp.net because there is an existing table in code first migration

I am developing a ASP.NET MVC website. For interacting with database, I am using Entity Framework with code first approach. But now I am having a problem in adding/migrating new table and entity to my model and database.
First I created a entity class
public class Category
{
public int Id { get; set; }
[Required]
[MaxLength(40)]
public String Name { get; set; }
[MaxLength(60)]
public String MmName { get; set; }
}
But for this entity, I created database manually. I did not use any migration command. Then I run the app and register a user using built-in identity registration system. So database tables are created successfully. Then I continued development. I was working fine. After I developed everything dealing with Category, I tried to add another entity and database table.
So I created a entity class like this
public class Region
{
public int Id { get; set; }
[Required]
[MaxLength(50)]
public String Name { get; set; }
[MaxLength(70)]
public String MmName { get; set; }
[MaxLength(30)]
public String GeoLocation { get; set; }
[MaxLength(200)]
public String Description { get; set; }
[MaxLength(250)]
public String MmDescription { get; set; }
}
Then I run the following command to update database
enable-migrations
add-migration "CreateRegion"
update-database
I got this error
Here is already an object named 'Category' in the database.
This is my initiaizer class
public class ContextInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<AyarDbContext>
{
protected override void Seed(AyarDbContext context)
{
}
}
How can I update database using command line? I want to migrate from command line because I am practising code first approach.
I see two options at this point:
1) Drop the table from the database and re run the migration. It will create both tables for you.
2) Modify the migration file so it's not trying to create the Category table. This goes against how Code First is supposed to work but you're already in that situation by having existing tables.

Invalid Column exception

Hi guys I am getting this exception when I try to run the vehicles page.
Invalid column name 'MakeID'.
I have two models:
public class Vehicle
{
public int VehicleID { get; set; }
public string Title { get; set; }
[ForeignKey("Make")]
public int MakeID { get; set; }
public virtual Make Make { get; set; }
}
public class Make
{
public int MakeID { get; set; }
public string Title { get; set; }
}
The error is being thrown in my vehicles controller here
public ActionResult Index()
{
var vehicles = db.Vehicles.Include(v => v.Make);
return View(vehicles.ToList());
}
Add/Enable Migrations. Update the Database. Most of the case improper update causes the issue. There is no problem with your above code.
Make sure: you have Updated the Database Tables after adding new columns.
Run the Update-Database command in Package Manager Console.
Make sure your column Foreign Key Relationship / Mappings are ok.
You have to check it out manually.
There are four ways to Drop and Create the Database. Based on several conditions. OR you can manually delete the Database from SQL Server.
Good Article and Source can be found here - Programatically.
Note: Recreating the Database will lose the entire existing data. There is one way to avoid this problem. It's providing Seed Data to the database / Tables on create.

NHibernate - Add Comment Property to Entities (Store with Join)

I have a system where I need to be able to add a Comment field onto Customer and Location models but I cannot touch the schema of the existing tables. However, I can add a Comments table. I have simplified this example. We would like the ability to add this Comment to more models moving forward they all use a Guid as Id.
This existing system is a 3rd party system with its own data access layer.
We are just starting to get into NHibernate. From what I can tell it looks like a Join map.
Example:
public class Customer
{
public Guid Id { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Comment { get; set; }
}
public class Location
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public string Address { get; private set; }
public string Comment { get; set; }
}
Note: we are sure we want the Comment as a 1-to-1 relationship and not a 1-to-many.
How do I configure a separate table just capture Id and Comment? I'm looking for the right terminology to use. I'm looking for examples with XML (and if possible Fluent config). I would like to keep the Comments for all objects in one table. Thanks.
If you can add Comment table (and corresponding key columns in the existing tables) than fluent mapping can look like
public class CustomerMap : ClassMap<Customer>{
public CustomerMap(){
//...other columns mappings
References(c=>c.Comment).Column("CommentId");
}
}
And repeat it for other entities as well. You can set desired fetch-mode(join) and other action there as well. I have wrote References there (so many-to-one) but if you need one-to-one mapping it is not a big difference
If you can't change the database schema your options are very limited.
MAYBE, you can do it using the mapping.
Take a look here:
http://ayende.com/blog/3961/nhibernate-mapping-join
Try to use the same column name in mapping for all entities.

Updating table fields not included in model Linq to Entities

So, I wanted to call this something like "Auditing Linq to Entities" or similar, but realize that doesn't quite encapsulate what I wanted to do. Simply put, our data modeler is required to put 4 columns on every single table within our aplication, even our cross-reference tables (the tables that represent the middle of a many-to-many relationship)
Anyhow, I've read a ton of articles that are about change tracking, which is close to what I want to do, but not exact. What I'm looking to do is to override the TSQL generation to append the column(s) that I need to update that are not included within the model.
Edit
Thinking more about this question, I realized that my example wasn't quite complete... imagine the User <---> Roles relationship and how that works. You typically create 3 tables: [Users], [Roles], and [UserRoles] which has 2 columns for referencing many users to many roles.
Now, imagine for all three tables, your loving DBA added 4 columns: CreatedBy, CreatedOn, UpdatedBy, UpdatedOn.
In Code, you'd probably have a Collection (list, collection, stack, etc.) of roles against each user, as in this C# code:
public class User
{
public int Id { get; set;}
public string Username { get; set;}
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Password { get; set; }
public List<Role> Roles { get; set; }
}
public class Role
{
public int Id {get; set; }
public string Code { get; set; }
public string Description { get; set; }
}
Has anyone successfully been able to update all the update and created columns without adding those fields to their model utilizing Entity Framework, and if so, can they provide examples of this?
Same question, but for NHibernate. If NHibernate will support this, but Entity Framework won't, I'm comfortable to persuade the powers-that-be to allow us to utilize NHibernate over Entity Framework, as I'll have a valid reason for this.
I have a very similar structure. The only ways to update the fields is to add them as properties to the objects (I encapsulate them in a AuditInfo class) or to use triggers. Users are shown the audit fields in my application so I have to have them available as properties anyway. NHibernate is so extensible that you can accomplish what you propose but it would be ugly.
In my case the triggers aren't sufficient because our application has its own user management so I have to set the xBy properties in the application. We also have the triggers in place as a backup and to record changes made outside of the application (data scrubs).
The many-to-many tables present a big problem because I would have to include them in the domain model in order to set the audit fields. I don't do that, so for those tables I only have the audit info available in the trigger (i.e. everything but the actual user name).
AuditInfo class:
[Serializable]
public sealed class AuditInfo
{
public AuditInfo()
{
SetCreated(string.Empty, DateTime.Now);
}
public string CreatedBy { get; private set; }
public DateTime CreatedDate { get; private set; }
public string RevisedBy { get; private set; }
public DateTime RevisedDate { get; private set; }
public string CreatedInfo
{
get { return "Created: " + CreatedDate.ToShortDateString() + " by " + CreatedBy; }
}
public string RevisedInfo
{
get { return "Revised: " + RevisedDate.ToShortDateString() + " by " + RevisedBy; }
}
internal void SetCreated(string createdBy, DateTime createdDate)
{
CreatedBy = createdBy;
CreatedDate = createdDate;
SetRevised(createdBy, createdDate);
}
internal void SetRevised(string revisedBy, DateTime revisedDate)
{
RevisedBy = revisedBy;
RevisedDate = revisedDate;
}
}
Interface implemented by auditable entities:
public interface IAuditable
{
AuditInfo AuditInfo { get; }
}

Categories