Migrations not creating all fields from class - c#

I'm using ASP.NET MVC 5. When creating a new migration it is generating the some tables correctly. However, classes like the one below are being generated with almost all of the fields missing in migration script.
public class Meeting
{
public int ID { get; set; }
[Display(Name = "Meeting Topic")]
public string MeetingTopic;
[Display(Name = "Meeting Minutes")]
public int MeetingMinutes;
public ICollection<MeetingTopic> MeetingTopics { get; set; } = new HashSet<MeetingTopic>();
[Display(Name = "Meeting Documents")]
public ICollection<MeetingDocuments> MeetingDocuments { get; set; } = new HashSet<MeetingDocuments>();
[Display(Name = "Meeting Notes")]
[StringLength(100, ErrorMessage = "100 characters limit.")]
public string MeetingNotes { get; set; }
}
The SQL table create script being created from the migration which is missing all the field except for MeetingNotes
migrationBuilder.CreateTable(
name: "Meeting",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
MeetingNotes = table.Column<string>(type: "TEXT", maxLength: 100, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Meeting", x => x.ID);
});
So far I've tried deleting all migrations and even the database and rebuilding but the new migration still return the same table with missing fields.
If anyone has any idea of what could be causing it would be very helpful. Thanks

Related

ASP.NET Core 5 & Entity Framework : convention based navigation problems

I have an ASP.NET MVC app that uses Entity Framework with convention based navigation and it works great. I decided to experiment moving
to ASP.NET Core 5 with Entity Framework Core v5.0.6. Well not easy, what a bear as the conventions for one to many break down. Afraid to try my many-to-many!
I have extended IdentityUser to include a navigation property of List<BookedDates> :
public class ApplicationUser : IdentityUser
{
public int skillLevel { get; set; }
public int timesCaptain { get; set; }
public int bFreezeDB { get; set; }
public string memberName { get; set; }
public virtual List<BookedDates> bookedDates { get; set; }
public virtual List<Match> Matches { get; set; }
public ApplicationUser()
{
bFreezeDB = 0;
}
}
Now a user can have many BookDates:
public class BookedDates
{
public int id { get; set; }
public int month { get; set; }
public virtual ApplicationUser user { get; set; }
public string status { get; set; }
}
The initial migration code looks good as seems to have picked up foreign key relations:
migrationBuilder.CreateTable(
name: "statusforDays",
columns: table => new
{
id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(max)", nullable: true),
month = table.Column<int>(type: "int", nullable: false),
status = table.Column<string>(type: "nvarchar(max)", nullable: true),
ApplicationUserId = table.Column<string>(type: "nvarchar(450)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_statusforDays", x => x.id);
table.ForeignKey(
name: "FK_statusforDays_AspNetUsers_ApplicationUserId",
column: x => x.ApplicationUserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
Then in my Controller I make following call:
ApplicationUser user = _db.Users
.Include(u => u.bookedDates)
.Where(u => u.Email == email)
.SingleOrDefault();
I get this error:
'Microsoft.Data.SqlClient.SqlException' in Microsoft.EntityFrameworkCore.Relational.dll
An exception of type 'Microsoft.Data.SqlClient.SqlException' occurred in Microsoft.EntityFrameworkCore.Relational.dll but was not handled in user code
Invalid column name 'userId'.
Where is userid coming from? I know I can probably use Fluent and create the relation but I thought EF Core 5 was supposed to handle simple convention based navigation much better than v3
I always suggest the FluentApi approach because this gives you more control over the relations.
In your BookedDates class you have the navigation property: public virtual ApplicationUser user { get; set; }. By convention EF Core search the name of the property followed by Id as a foreign key column: userId like the error shows.
Rename the property as public virtual ApplicationUser ApplicationUser { get; set; } and the convention will search for ApplicationUserId field in the table instead userId.

System.Data.Entity.Core.EntityCommandExecutionException and Inner Exception SqlException: Invalid column name 'xxxx'

This is regarding an exception when trying to fetch values to a Datagrid from a database.
When I try to run the application I got the below-mentioned error as,
System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
Inner Exception
SqlException: Invalid column name 'AssetClass_Id'.
This above mentioned foreign key column AssetClass_Id has been modified as AssetClassId when updating the database from migration. The database shows its column value as AssetClassId in the design too.
Here is my AssetType class code:
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[StringLength(100)]
public string Description { get; set; }
public AssetClass AssetClass { get; set; }
Here is my .cs file code which written under form load method:
using (CapexDbContext db = new CapexDbContext())
{
// Load data to grdAssetType
assetTypeBindingSource.DataSource = db.AssetTypes.ToList();
AssetType obj = assetTypeBindingSource.Current as AssetType;
panelAssetType.Enabled = false;
// Load data to cmbAssetClasses
var assetClass_ = from AssetClass in db.AssetClasses
select AssetClass;
cmbAssetClass.DataSource = assetClass_.ToList();
cmbAssetClass.DisplayMember = "Name";
cmbAssetClass.ValueMember = "Id";
}
The exception coming from this line when trying to fetch data to the dataGrid:
assetTypeBindingSource.DataSource = db.AssetTypes.ToList();
Additionally here is my latest migration code:
CreateTable(
"dbo.AssetClasses",
c => new
{
Id = c.Int(nullable: false, identity: true),
Code = c.String(nullable: false, maxLength: 10),
Name = c.String(nullable: false, maxLength: 100),
Lifetime = c.Int(nullable: false),
Rate = c.Single(nullable: false),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AssetTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: 50),
Description = c.String(maxLength: 100),
AssetClassId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AssetClasses", t => t.AssetClassId)
.Index(t => t.AssetClassId);
Running DB Tables : AssetTypes & AssetClass(referring table)
Try to give a look to the DBcontext in your project, try to see waht it does say in the definition of the entity, especialy in this part:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//modelBuilder.Entity<IdentityUser>().ToTable("user");
modelBuilder.Entity<ApplicationUser>(entity =>
{
entity.ToTable("user");
entity.Property(e => e.CreationAtDate)
.HasColumnName("created_at") //<------ THIS ONE
.HasDefaultValueSql("(getDate())");
});
I noticed that your AssetType class contains AssetClass property.
Meanwhile, the table in your database contains the AssetClassId field.
They are different.
Therefore, we should define the class in the AssetType class.
public class AssetType
{
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[StringLength(100)]
public string Description { get; set; }
public int AssetClassID { get; set; } // We need to modify it here
}
Then, we need to execute the command to update the database in the package manager console.
PM> Add-Migration Modify
PM> Update-Database
Finally, we can use the following code to show data in the datagirdview.
private void Form1_Load(object sender, EventArgs e)
{
using (var db = new MyContext())
{
var type = new AssetType { Id = 1001, Description = "test1", Name = "name1", AssetClassID=123456 };
db.Types.Add(type);
db.SaveChanges();
dataGridView1.DataSource = db.AssetTypes.ToList();
}
}
Result:

C# Entity Framework Error: "SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_718"

I'm fairly new to using Entity Framework, and cannot figure out this error. I am pulling data from an excel sheet and putting it into a database with EF. There are other posts for this issue, but after going through them, nothing seemed to work.
To finish off my error statement, it says: "The conflict occurred in the database 'DataWarehouse', table 'dbo.RVTools_vSwitch', column 'vSwitch_id'." In following the paper trail on this, I can confirm that there is a column 'vSwitch_id' in the dbo.RVTools_vSwitch table. vSwitch is one of the sheets in my excel file, and the vSwitch_id is automatically made by EF.
When I try to import data from a different excel sheet, vPort, I run into the issue. One of the items that needs to be imported into the database is a vSwitch_id. So I have a GetID function that uses a few parameters given by the excel sheet to find the correct ID, however this still doesn't work.
The next thing I tried was looking through the classes for vPort and vSwitch that contain the EF calls to add data into the database and the migrations to check that everything that was needed was there, but couldn't find any issues there.
So if I have the correct migrations, correct classes, correct data from excel, and I have the correct tables and rows in my database, what else could be causing this error?
Here is the code for importing the data from excel to the database. VSwitchId is where the error is and vPort is the sheet I'm importing:
foreach (DataRow dataRow in Data.Rows)
{
context.RvtoolsVPort.Add(new RvtoolsVPort
{
PortGroup = dataRow[0].ToString(),
Vlan = Convert.ToInt32(dataRow[1]),
PromiscuousMode = Convert.ToBoolean(bool.Parse(dataRow[2].ToString())),
MacChanges = Convert.ToBoolean(bool.Parse(dataRow[3].ToString())),
ForgedTransmits = Convert.ToBoolean(bool.Parse(dataRow[4].ToString())),
TrafficShaping = Convert.ToBoolean(bool.Parse(dataRow[5].ToString())),
Width = Convert.ToInt32(dataRow[6]),
Peak = Convert.ToInt32(dataRow[7]),
Burst = Convert.ToInt32(dataRow[8]),
Policy = dataRow[9].ToString(),
ReversePolicy = Convert.ToBoolean(bool.Parse(dataRow[10].ToString())),
NotifySwitch = Convert.ToBoolean(bool.Parse(dataRow[11].ToString())),
RollingOrder = Convert.ToBoolean(bool.Parse(dataRow[12].ToString())),
Offload = Convert.ToBoolean(bool.Parse(dataRow[13].ToString())),
Tso = Convert.ToBoolean(bool.Parse(dataRow[14].ToString())),
ZeroCopyXmit = Convert.ToBoolean(bool.Parse(dataRow[15].ToString())),
VSwitchId = vSwitch.GetID(dataRow[19].ToString(), dataRow[16].ToString(), dataRow[18].ToString(), dataRow[17].ToString(), assessment_id),
AssessmentId = assessment_id
});
context.SaveChanges();
}
Here is the class for vPort:
namespace KelderModel
{
public partial class RvtoolsVPort
{
public int VPortId { get; set; }
public string PortGroup { get; set; }
public int? Vlan { get; set; }
public bool? PromiscuousMode { get; set; }
public bool? MacChanges { get; set; }
public bool? ForgedTransmits { get; set; }
public bool? TrafficShaping { get; set; }
public int? Width { get; set; }
public int? Peak { get; set; }
public int? Burst { get; set; }
public string Policy { get; set; }
public bool? ReversePolicy { get; set; }
public bool? NotifySwitch { get; set; }
public bool? RollingOrder { get; set; }
public bool? Offload { get; set; }
public bool? Tso { get; set; }
public bool? ZeroCopyXmit { get; set; }
public int VSwitchId { get; set; }
public int AssessmentId { get; set; }
public virtual Assessment Assessment { get; set; }
public virtual RvtoolsVSwitch VSwitch { get; set; }
}
}
Finally, here is the code in my migration for vPort:
migrationBuilder.CreateTable(
name: "RVTools_vPort",
columns: table => new
{
vPort_id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
port_group = table.Column<string>(unicode: false, maxLength: 255, nullable: true),
vlan = table.Column<int>(nullable: true),
promiscuous_mode = table.Column<bool>(nullable: true),
MAC_changes = table.Column<bool>(nullable: true),
forged_transmits = table.Column<bool>(nullable: true),
traffic_shaping = table.Column<bool>(nullable: true),
width = table.Column<int>(nullable: true),
peak = table.Column<int>(nullable: true),
burst = table.Column<int>(nullable: true),
policy = table.Column<string>(unicode: false, maxLength: 255, nullable: true),
reverse_policy = table.Column<bool>(nullable: true),
notify_switch = table.Column<bool>(nullable: true),
rolling_order = table.Column<bool>(nullable: true),
offload = table.Column<bool>(nullable: true),
TSO = table.Column<bool>(nullable: true),
zero_copy_xmit = table.Column<bool>(nullable: true),
vSwitch_id = table.Column<int>(nullable: false),
assessment_id = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RVTools_vPort", x => x.vPort_id);
table.ForeignKey(
name: "FK_849",
column: x => x.assessment_id,
principalTable: "Assessment",
principalColumn: "assessment_id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_718",
column: x => x.vSwitch_id,
principalTable: "RVTools_vSwitch",
principalColumn: "vSwitch_id",
onDelete: ReferentialAction.Restrict);
});
Could there be some issues in the migration with the constraints? Thank you for any help you might bring.

EF Core - Table columns are automatically sorting

I have just added a few new models to my .NET Core application that is currently using EF code-first migrations. Previous models have migrated fine and in the order of my model properties, but things seem to have changed now. New models are sorted first by key values, then alphabetically.
Here's an example...
My logging class:
[Table("Logs")]
public class LogEntry
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
public LogEntryType Type { get; set; }
[StringLength(4000)]
public string Message { get; set; }
[StringLength(4000)]
public string StackTrace { get; set; }
public DateTime LogTimeUtc { get; set; } = DateTime.UtcNow;
}
I type into my package manger console in VS 2017:
add-migration InitialCreate -Context LoggingContext
and that produces this in the migration builder:
migrationBuilder.CreateTable(
name: "Logs",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
LogTimeUtc = table.Column<DateTime>(type: "datetime2", nullable: false),
Message = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true),
StackTrace = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true),
Type = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Logs", x => x.Id);
});
Notice that the order of the properties have changed? This same ordering is then applied to the database when using:
update-database -Context LoggingContext
How can I get EF Core to stop ordering my columns? The last time I made a new table for this application (using the exact same method, 2 months back) it retained its order, and I don't think I've done anything to it since.
It happens in 2.0, EF Core 2.1 or after updates migrations to initially generate columns for tables in the same order as properties are declared in classes.Refer to here.

EF Code first set a foreign key with an empty lookup table

I have a problem with EF code first migration related to a lookup table and foreign keys. Let's say I have this two classes in my code:
public class Test
{
[Key]
public long Id { get; set; }
[Required]
public string Title { get; set; }
[Required, DisplayName("Test type")]
public TestType TestType { get; set; }
}
public class TestType
{
public int Id { get; set; }
public string Name { get; set; }
}
TestType is a typical lookup table and I usually fill them up in the Seed() method:
context.TestTypes.AddOrUpdate(
it => it.Name,
new TestType() { Name = "Drug" },
new TestType() { Name = "Educational" },
new TestType() { Name = "Other" }
);
When I create the table with the relationship I get the following migration:
CreateTable(
"dbo.TestTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
AddColumn("dbo.Tests", "TestType_Id", c => c.Int(nullable: false));
CreateIndex("dbo.Tests", "TestType_Id");
AddForeignKey("dbo.Tests", "TestType_Id", "dbo.TestTypes", "Id", cascadeDelete: true);
Now, if I perform the migration of course I will get an error since the foreign key cannot be respected given the fact that the lookup table is still empty and the column created does not have a default value.
In DEVELOPMENT I am able to solve this by simply creating two migrations, the first one to create the lookup table and the second one to set the foreign key. If I run them separately then the Seed method after the first one will fill the table and I can tweak the column creation to pick up the values from the DB to prefill the column before creating the foreign key, a bit like this:
AddColumn("dbo.Tests", "TestType_Id", c => c.Int(nullable: false));
Sql("UPDATE dbo.Tests SET TestType_Id = (SELECT TOP 1 Id FROM dbo.TestTypes)");
CreateIndex("dbo.Tests", "TestType_Id");
AddForeignKey("dbo.Tests", "TestType_Id", "dbo.TestTypes", "Id", cascadeDelete: true);
Then when I run it everything works.
Now, in PRODUCTION I don't have the same luxury, since ALL the migrations are run before the Seed method is run, I will always have the same problem.
I know I could potentially run the migrations in stepped order on the production DB as well but that does not really solve the problem... Let's say a colleague of mine updates his working copy and runs the migrations, all will be run in order and he will encounter the error for sure.
I'm not sure on the current state of your database but I would define your models like this
public class Test
{
[Key]
public long Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
[ForeignKey("TestType")]
public int TestTypeId { get; set; }
[DisplayName("Test type")]
public virtual TestType TestType { get; set; }
}
public class TestType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
Which results in the following migration when the tables don't exist already. I always find describing the foreign keys explicitly works better.
public override void Up()
{
CreateTable(
"dbo.Tests",
c => new
{
Id = c.Long(nullable: false, identity: true),
Title = c.String(nullable: false),
TestTypeId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.TestTypes", t => t.TestTypeId)
.Index(t => t.TestTypeId);
CreateTable(
"dbo.TestTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
}
The seed should then work fine as long as the Test table is empty?

Categories

Resources