We now use EntityFramework CodeFirst Migration.
Our database table and index was created long time ago, before we use EntityFramework CodeFirst Migration.
Our table is myTable, with a column vchMyColumnA and index ColumnA.
Since we used EntityFramework CodeFirst Migration, we have used EntityFramework CodeFirst Migration to add new columns to myTable.
We need to drop Index ColumnA.
Do we need to do it thru EntityFramework CodeFirst Migration, or can we just run a script to drop the index ?
If we need to drop the index thru EntityFramework CodeFirst Migration, how can I do it ? In Package Manager Console, I typed add-migration DropColumnAIndex, and open the migration code DropColumnAIndex, and added this code:
public partial class DropColumnAIndex : DbMigration
{
public override void Up()
{
DropIndex("dbo.myTable", new[] { "ColumnA" });
}
public override void Down()
{
CreateIndex("dbo.myTable", "vchMyColumnA");
}
}
Then I typed update-database.
There is no error, and I can see the migration in the database (select * from __MigrationHistor), but index ColumnA is still there.
Thank you.
Sorry, hard to write this in a comment. You can inject the equivalent SQL into your migration:
public override void Up()
{
Sql("DROP INDEX ColumnA ON [dbo].[myTable];");
}
Related
I'm trying to set Id manually for some entries.
I have a Customer class with an Identity field
modelBuilder.Entity<Customer>().Property(f => f.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
and in the insert part I have
using (var transaction = ctx.Database.BeginTransaction())
{
ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] ON");
ctx.Customers.AddRange(customersList);
ctx.SaveChanges();
ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] OFF");
transaction.Commit();
}
but I'm still getting the exception
Explicit value must be specified for identity column in table
'Customers' either when IDENTITY_INSERT is set to ON or when a
replication user is inserting into a NOT FOR REPLICATION identity
column.
In the StateEntries of my exception, I can see that all the fields that are stored in another table like "Contacts" seems to be the cause
customer.Contacts = new List<Contact> {new Contact {Name = "Test", … }}
How can I make it work?
That error message is misleading. You are succeeding in turning IDENTITY_INSERT on, but EF is still generating an INSERT statement under the assumption that the key value will be generated by the IDENTITY column.
So you additionally must generate an INSERT statement containing the key value. You can, of course, use .ExecuteSqlCommand() to perform the INSERT as well. Or you can get EF to do it, but you must use a model where that Entity does not have database-generated keys. OnModelCreating configures the model only once per ModelType, so you can't just put a switch in there.
Instead you can create a subtype of your DbContext for seeding, overriding the entity configuration of the base DbContext. Like this:
class Db_Seed: Db
{
public Db_Seed(string constr) : base(constr)
{
Database.SetInitializer<Db_Seed>(null); //no initializer
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Customer>().Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
You still must set IDENTITY_INSERT on (since the table does have an IDENTITY), but with this context EF will not generate an INSERT statement that assumes the server will generate the key.
Say I have a table in the database with data already populated (imported from excel).
I am building an MVC website using .NET Core and EF Core (both v.1.1.2)
What I'm wanting to do create a series of models, whose data is derived from one original "source data" table. The source data table has 150 columns, and although I don't need them all right now, I do want to retain all columns so that I might be able to use them at a later time if needed.
Using the "dotnet ef dbcontext scaffold" command, I was able to generate a:
Model - with all public get/set properties for each column
DbContext Class - with DbSet & Fluent API statements to reference the table and columns
With this setup, is it possible to setup a sort of "virtual" relational data model with EF Core by simply creating various Model classes (many-to-many relationships) and their properties equal to the properties already defined in the original "source" entity?
What I'm hoping to avoid is having to maintain an actual relational data structure in the DB (independent tables linked by PKs, FKs, join tables, etc.)
Reason being... I'll only be looking to do a nightly update of the source data table from bulk import of Excel worksheet and will not have to persist or track any changes to the data (read only). So, I'd like to not have to deal with the additional overhead/setup/maintenance involved with mapping the source data to relational tables, columns, keys, etc. during the import.
Can I simply create various models, then in the DbContext, override the OnModelCreating method passing an instance of modelBuilder to map those DbSet entities to the columns in the source table?
namespace VTracker.Contexts
{
public partial class DataContext : DbContext
{
public DataContext(DbContextOptions options) : base(options)
{
}
public DbSet<SourceData> Data { get; set; }
public DbSet<SomeModel1> Model1 { get; set; }
public DbSet<SomeModel2> Model2 { get; set; }
public DbSet<SomeModel3> Model3 { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SourceData>(entity =>
{
// some key must be defined?
entity.HasKey(e => e.SourceIDColumn);
entity.ToTable("SourceDataTable");
entity.Property(e => e.SourceIDColumn)
entity.Property(e => e.SourceColumn1)
.HasColumnName("SourceColumn1")
// ...... continue mapping .....
// Some Model 1 Entity Builder
entity.ToTable("SourceDataTable");
// ...... continue mapping .....
// Some Model 2 Entity Builder
entity.ToTable("SourceDataTable");
// .... and so on for other models......
}
}
}
}
Or would it be better to just use the one entity for everything and just build out SQL / LINQ queries to retrieve/join the data as needed?
I have got a database first approach with EF5 and here is a fragment of mappings:
internal class xxxMapping : EntityTypeConfiguration<Order>
{
public xxxMapping ()
{
ToTable("my_table");
//......
HasMany(it => it.Documents)
.WithMany()
.Map(
m =>
{
m.ToTable("dependent_table");
m.MapLeftKey("left_key_id");
m.MapRightKey("right_key_id");
});
}
What is the best way to declare, using fluent API, that when some row is deleted from my_table, then dependent rows from dependent_table will be deleted too (Cascade delete option in FK)
UPD It seems to be working without any additional code (Of course - if foreign key in table is configured properly). But i'm not sure it's a good practice to do so
I'm using EF 5 Code First. I have the following Fluent API code that sets a navigation property for 'SaleZipCode'.
private void MyTable(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyType>()
.HasRequired(a => a.SaleZipCode)
.WithMany()
.Map(map => map.MapKey("SaleZipCodeId"));
}
I realize I misnamed 'SaleZipCode' and it should be 'ZipCode'. However, when I do this, EF attempts to drop the SaleZipCode column and add a ZipCode column when I do an Update-Database, instead of just doing a rename. This doesn't work because I have existing data in the table. Is there a way I can get EF to do a rename and not a drop and recreate?
Renaming property in your entity should not affect database, because there is no SaleZipCode column in database. Foreign key is mapped to SaleZipCodeId column, and only changing this foreign key column mapping will affect database. E.g. if you will change mapping to
modelBuilder.Entity<MyType>()
.HasRequired(a => a.Foo) // changing this will not affect database
.WithMany()
.Map(map => map.MapKey("ZipCodeId")); // column name changed
Then following migration will be generated
public override void Up()
{
RenameColumn(table: "dbo.MyTypes",
name: "SaleZipCodeId", newName: "ZipCodeId");
}
public override void Down()
{
RenameColumn(table: "dbo.MyTypes",
name: "ZipCodeId", newName: "SaleZipCodeId");
}
Simple renaming columns, data will be preserved.
In my WCF service I am using Entity Framework .NET 4.0,
in my database i have this table:
CREATE TABLE [dbo].[Tracking](
[TrackingID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
...
CONSTRAINT [PK_Tracking] PRIMARY KEY CLUSTERED
(
[TrackingID] ASC
)
) ON [DATA]
ALTER TABLE [dbo].[Tracking] ADD CONSTRAINT [DF_Tracking_TrackingID] DEFAULT (newid()) FOR [TrackingID]
GO
when i insert a record Entity framewrok has prepopulated the TrackingID as "00000000-0000-0000-0000-000000000000". I have setting field property to be Computed and Identity bu no such luck any ideas: here is my code snippet:
using (var context = new DB.PTLEntities())
{
var tracking = new DB.Tracking();
context.Trackings.AddObject(tracking);
context.SaveChanges();
trackingID = tracking.TrackingID;
}
Looks like EF doesnt think this column is an identity column so its putting in default(Guid). Take a look here for some details on making a guid an identity column (it actually goes through your exact example) http://leedumond.com/blog/using-a-guid-as-an-entitykey-in-entity-framework-4/
I got same issue. Following solution worked for me.
There is a need to change the StoreGeneratedPattern value for the property in the EF designer. Set it to Identity. This will cause EF to avoid setting the value on an insert, then capture it after the insert is complete.
If your EF version is 4, then you may have trouble with this using the designer only. You may have to edit the .edmx manually and set the StoreGeneratedPattern in the storage model itself.
Example:
< Property Name="EmpId" Type="uniqueidentifier" Nullable="false" StoreGeneratedPattern="Identity" />
In my case (EF >= 4.1) I needed to add a default to the table itself:
ALTER TABLE MyTable ADD DEFAULT (newid()) FOR [Id]
Also if you're using your own context, you should tell EF that the column is the identity column:
public class ShedContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DraftFromWebOneOff>()
.Property(d => d.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
}