EF Migrations DropForeignKey fails when key is in a base class - entity-framework-migrations

I'm attempting to update my data models for an EF 5.0.0-rc code-first class library. The first command in the Up() method is
DropForeignKey("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" }, "dbo.ChileProducts");
but I'm getting a SqlException: 'FK_dbo.ChileInventory_dbo.ChileProducts_LotInventoryItemTypeId_ChileProductId' is not a constraint. Could not drop constraint.
I think that the cause for the error is due to the fact that my ChileProducts class get's it's key properties from its base class. Since there is no overload of the DropForeignkey method which accepts the principal column name(s), I believe EF is unable to determine the correct constraint to drop. I should also point out that the constraint name displayed in the exception message does not match up with the constraint name in the database (hence the error...)
Below you'll find the data models and the migration methods. But first a quick note about the nature of the change behind the migration: Each derivative of the InventoryBase class defines product type through the composite key of InventoryTypeId and [InventoryTypeSpecific]ProductId. For example, ChileInventory would identify it's particular chile type type as InventoryItemTypeId = [ChileInventoryTypeId] and ChileProductId = [ChileProductId]. PackagingInventory would identify it's packaging type as InventoryItemTypeId = [PackagingInventoryTypeId] and PackagingProductId = [PackagingProductId]. And so on.
The model change I'm working to roll out is the elevation of the [InventoryTypeSpecific]ProductId from each InventoryBase derivative into the base. This would result in all InventoryBase derived objects sharing a common ProductId property which, in conjunction with the InventoryItemTypeId, would enable navigation from InventoryBase to ProductBase; which isn't possible in the previous model.
Thanks, in advance for your advice and consideration.
--Vinney
Data Models
Chile Product
public abstract class ProductBase
{
[Key]
[Column(Order = 0)]
public virtual int InventoryItemTypeId { get; set; }
[Key]
[Column(Order = 1)]
public virtual int Id { get; set; }
[StringLength(150)]
public virtual string Name { get; set; }
[ForeignKey("InventoryItemTypeId")]
public virtual InventoryItemType InventoryItemType { get; set; }
public virtual bool IsActive { get; set; }
}
public class ChileProduct : ProductBase
{
public virtual int ChileTypeId { get; set; }
[ForeignKey("ChileTypeId")]
public virtual ChileType ChileType { get; set; }
}
Chile Inventory
public abstract class InventoryBase
{
[Key]
[Column(Order = 0, TypeName = "Date")]
public virtual DateTime DateCreated { get; set; }
[Key]
[Column(Order = 1)]
public virtual int Sequence { get; set; }
[Key]
[Column(Order = 2)]
public virtual int LotInventoryItemTypeId { get; set; }
[Column(TypeName = "Date")]
public virtual DateTime LotDateCreated { get; set; }
public virtual int LotSequence { get; set; }
public virtual int ProductId { get; set; }
[ForeignKey("LotInventoryItemTypeId, LotDateCreated, LotSequence")]
public virtual Lot Lot { get; set; }
[ForeignKey("LotInventoryItemTypeId")]
public virtual InventoryItemType ItemType { get; set; }
public virtual ICollection<InventoryQuantityByLocation> QuantitiesByLocation { get; set; }
[ForeignKey("LotInventoryItemTypeId, ProductId")]
public virtual ProductBase ProductBase { get; set; }
}
public class ChileInventory : InventoryBase
{
[Column(TypeName = "Date")]
public virtual DateTime? ProductionBatchDateCreated { get; set; }
public virtual int? ProductionBatchSequence { get; set; }
public virtual int PackagingInventoryItemTypeId { get; set; }
public virtual int PackagingProductId { get; set; }
[ForeignKey("ProductionBatchDateCreated, ProductionBatchSequence")]
public virtual ProductionBatch ProductionBatch { get; set; }
[ForeignKey("LotInventoryItemTypeId, ProductId")]
public virtual ChileProduct ChileProduct { get; set; }
[ForeignKey("PackagingInventoryItemTypeId, PackagingProductId")]
public virtual PackagingProduct PackagingProduct { get; set; }
}
Migration
public override void Up()
{
DropForeignKey("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" }, "dbo.ChileProducts");
DropForeignKey("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" }, "dbo.PackagingProducts");
DropForeignKey("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" }, "dbo.AdditiveProducts");
DropIndex("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" });
DropIndex("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" });
DropIndex("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" });
AddColumn("dbo.Inventory", "ProductId", c => c.Int(nullable: false));
AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
DropColumn("dbo.ChileInventory", "ChileProductId");
DropColumn("dbo.PackagingInventory", "PackageId");
DropColumn("dbo.AdditiveInventory", "AdditiveProductId");
}
public override void Down()
{
AddColumn("dbo.AdditiveInventory", "AdditiveProductId", c => c.Int(nullable: false));
AddColumn("dbo.PackagingInventory", "PackageId", c => c.Int(nullable: false));
AddColumn("dbo.ChileInventory", "ChileProductId", c => c.Int(nullable: false));
DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
DropColumn("dbo.Inventory", "ProductId");
CreateIndex("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" });
CreateIndex("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" });
CreateIndex("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" });
AddForeignKey("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
AddForeignKey("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" }, "dbo.PackagingProducts", new[] { "InventoryItemTypeId", "Id" });
AddForeignKey("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" }, "dbo.ChileProducts", new[] { "InventoryItemTypeId", "Id" });
}

Here's one work around I found:
Use the DropForeignKey overload which contains the parameters principalName and name -- which in this case means constraint name! It's a little more fragile becuase it requires the knowledge of the constraint name upfront but it works as expected.

If your initial model was created with the EF 4.3 then you will have such errors in EF 5.0 since the rules for generating PK/FK constraint names have changed between these two versions of the EF.
See this question for details and another possible solution.

Related

.NET Core 5.0 EF Migration add new foreign column

I have an application with .net core Entity Framework code first.
I have 2 tables in relationships.
altKategori and anaKategori
altKategoris
public class altKategori
{
[Key]
public int idAltKategori { get; set; }
[Column(TypeName = "Varchar")]
[StringLength(30)]
public string adAltKategori { get; set; }
public int idAnaKategori { get; set; }
public anaKategori anaKategori { get; set; }
}
anaKategoris
public class anaKategori
{
[Key]
public int idAnaKategori { get; set; }
[Column(TypeName = "Varchar")]
[StringLength(30)]
public string adAnaKategori { get; set; }
public List<altKategori> altKategoris { get; set; }
}
Also there is my Context:
public class Context : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=.\\MSSQLSERVER2019;database=deneme;User ID=deneme1;Password=****;");
}
public DbSet<altKategori> altKategoris { get; set; }
public DbSet<anaKategori> anaKategoris { get; set; }
}
When I start migration, migration automatic add anaKategoriidAnaKategori columns, and add relationship with that column.
migrationBuilder.CreateTable(
name: "altKategoris",
columns: table => new
{
idAltKategori = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
adAltKategori = table.Column<string>(type: "Varchar(30)", maxLength: 30, nullable: true),
idAnaKategori = table.Column<int>(type: "int", nullable: false),
anaKategoriidAnaKategori = table.Column<int>(type: "int", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_altKategoris", x => x.idAltKategori);
table.ForeignKey(
name: "FK_altKategoris_anaKategoris_anaKategoriidAnaKategori",
column: x => x.anaKategoriidAnaKategori,
principalTable: "anaKategoris",
principalColumn: "idAnaKategori",
onDelete: ReferentialAction.Restrict);
});
I don't want to relation with anaKategoriidAnaKategori. I want to relation with idAnaKategori. How can I?
Thanks for your help.
try to add relation attributes
public class altKategori
{
[Key]
public int idAltKategori { get; set; }
[Column(TypeName = "Varchar")]
[StringLength(30)]
public string adAltKategori { get; set; }
public int idAnaKategori { get; set; }
[ForeignKey(nameof(idAnaKategori ))]
[InverseProperty("altKategoris")]
public anaKategori anaKategori { get; set; }
}
public class anaKategori
{
[Key]
public int idAnaKategori { get; set; }
[Column(TypeName = "Varchar")]
[StringLength(30)]
public string adAnaKategori { get; set; }
[InverseProperty(nameof(altKategori.anaKategori))]
public List<altKategori> altKategoris { get; set; }
}

Execute Sql query in entity framework

I have a jquery data table in which i want to show a summarise report generated from sql query, but i am not able to do it, it shows error in the query. The summarise report consist of all month name and number of entries in every month.
Error:
System.Data.Entity.Core.EntityCommandExecutionException: 'The data reader is incompatible with the specified 'DHIFeedbackModel.FeedBack'. A member of the type, 'FeedbackUserName', does not have a corresponding column in the data reader with the same name.'
public ActionResult LoadData()
{
using (DHIFeedbackEntities2 Ms = new DHIFeedbackEntities2())
{
//var summary = Ms.FeedBacks.SqlQuery("select * from [DHIFeedback].[dbo].[FeedBack]").ToList<FeedBack>();
var summary = Ms.FeedBacks.SqlQuery(
#"SELECT *
FROM
(
SELECT
YEAR([FeedBackDate])[Year],DATENAME(MONTH, [FeedBackDate])[Month],
COUNT(1)[FeedbackID]
FROM
[DHIFeedback].[dbo].[FeedBack]
GROUP BY
YEAR([FeedBackDate]
),
DATENAME(MONTH, [FeedBackDate])) AS Monthlyupdate
PIVOT(SUM([FeedbackID]) FOR Month IN([January],[February],[March],[April],[May],[June],[July],[August],[September],[October],[November],[December])) AS MNamePivot
order by 1,2"
).FirstOrDefault<FeedBack>();
return Json(new { data = summary }, JsonRequestBehavior.AllowGet);
}
}
and the javascript:
$(document).ready(function () {
$('#Summary').DataTable({
"processing": true,
"ajax": {
"url": "/Summary/LoadData",
"type": "GET",
"datatype": "json",
},
"lengthMenu": [
[5, 10, 25, 50, 100, -1],
[5, 10, 25, 50, 100, "All"]
],
"autoWidth": true,
"responsive": true,
"lengthChange": true,
"ordering": true,
"fnRowCallback": function (nRow, aData, iDisplayIndex) {
var oSettings = this.fnSettings();
$("td:first", nRow).html(oSettings._iDisplayStart + iDisplayIndex + 1);
return nRow;
},
"columns": [
{ "data":"Year", "autoWidth": true },
{ "data":"January", "autoWidth": true },
{ "data":"February", "autoWidth": true },
{ "data":"March", "autoWidth": true },
{ "data":"April", "autoWidth": true },
{ "data":"May", "autoWidth": true },
{ "data":"June", "autoWidth": true },
{ "data":"July", "autoWidth": true },
{ "data":"August", "autoWidth": true },
{ "data":"September", "autoWidth": true },
{ "data":"October", "autoWidth": true },
{ "data":"November", "autoWidth": true },
{ "data":"December", "autoWidth": true }
]
});
});
public partial class FeedBack
{
public int FeedbackID { get; set; }
public string FeedbackUserName { get; set; }
public string FeedBackUserEmailID { get; set; }
public string FeedBackComment { get; set; }
public string Designation { get; set; }
public string Organization { get; set; }
public string ContactNo { get; set; }
public string City { get; set; }
public Nullable<System.DateTime> FeedBackDate { get; set; }
public Nullable<double> IsPublished { get; set; }
public string Reply { get; set; }
public Nullable<double> IsReplied { get; set; }
public Nullable<System.DateTime> ReplyDate { get; set; }
public string ReplyBy { get; set; }
public string Sector { get; set; }
public Nullable<int> Status { get; set; }
public int Year { get; set; }
public int January { get; set; }
public int February { get; set; }
public int March { get; set; }
public int April { get; set; }
public int May { get; set; }
public int June { get; set; }
public int July { get; set; }
public int August { get; set; }
public int September { get; set; }
public int October { get; set; }
public int November { get; set; }
public int December { get; set; }
public string Monthlyupdate { get; set; }
public string Month{ get; set; }
[NotMapped]
public List<FeedBack> FeedBackCollection { get; set; }
the error means that the ORM is expecting a resultset comprising each and every property of FeedBacks including the one named FeedbackUserName
So you need to edit the select clause of your sql to return all the expected columns.
or you may use
Ms.Database.SqlQuery<SomeType>(
"your query here").ToList();
where SomeType is :
public class SomeType {
public int Year {get; set;}
//... and/or all the pivoted columns
}

Orchard join between two types

i have three content types an applicationRecord, an ApplicationDetailRecord and a CustomerPartRecord, my applicationRecord looks like:
public virtual int Id { get; set; }
public virtual int CustomerId { get; set; }
public virtual DateTime CreatedAt { get; set; }
public virtual ApplicationStatus Status { get; set; }
public virtual CustomerPartRecord customer { get; set; }
public virtual IList<ApplicationDetailRecord> Details { get; protected set; }
now in my applicationService i have a getApplications() function like so:
public IQueryable<ApplicationRecord> GetApplications()
{
return _applicationRepository.Table;
}
when this runs it is returning all ApplicationDetailRecords but not the CustomerRecord. I also have two foreign key defined in my migration file which are
SchemaBuilder.CreateForeignKey("Application_Customer", "ApplicationRecord", new[] { "CustomerId" }, "CustomerPartRecord", new[] { "Id" });
SchemaBuilder.CreateForeignKey("ApplicationDetail_Application", "ApplicationDetailRecord", new[] { "ApplicationRecord_Id" }, "ApplicationRecord", new[] { "Id" });
i cant see any reason why the customer record isnt being returned, am i missing anything? how would i get this working?
Ok found the answer, my customerId in ApplicationRecord needed to be Customer_Id, after this it all worked fine!

navigation properties not saving

I have a simple object model
public class License
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ScaffoldColumn(false), StringLength(20)]
public string CreationUserId { get; set; }
[ScaffoldColumn(false), StringLength(20)]
public string LastModifiedUserId { get; set; }
public string LicenseName { get; set; }
public LicenseType LicenseType { get; set; }
public State State { get; set; }
public DateTime DateIssued { get; set; }
public int ValidFor { get; set; }
}
public class State
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ScaffoldColumn(false), StringLength(20)]
public string CreationUserId { get; set; }
[ScaffoldColumn(false), StringLength(20)]
public string LastModifiedUserId { get; set; }
[StringLength(2)]
[Required]
public string Name { get; set; }
[Display(Name = "Long Name")]
[Required, StringLength(25)]
public string LongName { get; set; }
}
public class LicenseType
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ScaffoldColumn(false), StringLength(20)]
public string CreationUserId { get; set; }
[ScaffoldColumn(false), StringLength(20)]
public string LastModifiedUserId { get; set; }
[StringLength(100), Required]
public string Description { get; set; }
}
I am using the hot towel template breeze, durandal, knockout.
I have a simple add view model
var _licenseAdded = false;
var vm = {
states: ko.observableArray(context.states),
licenseTypes: ko.observableArray(context.licenseTypes),
viewAttached: function () {
var self = this;
$('input[name^="date"]').datepicker();
$('#validFor').spinner({
min: 365,
max: 3650,
step: 30
});
log('add Attached', null, true);
},
activate: function () {
var self = this;
self.original = context.manager.createEntity('License', { licenseName: 'Testing321', dateIssued: moment().format('L') }, null);
log('add Activated', null, true);
},
canDeactivate: function () {
if (_licenseAdded === false) {
return app.showMessage('Are you sure you want to leave this page?', 'Navigate', ['Yes', 'No']);
} else {
return true;
}
},
saveChanges: function () {
$.when(context.saveNewLicense()).done(function () {
_licenseAdded = true;
});
router.navigateTo('home');
},
original: undefined
};
return vm;
And here is my add.html, everything binds up fine and works beautifully until saving.
When I call saveChanges the saveBundle sent to the controller has no navigation properties attached that allow for the correct State and LicenseType to be stored I only get:
saveBundle {
"entities": [
{
"Id": -1,
"CreationUserId": null,
"LastModifiedUserId": null,
"LicenseName": "new for testing",
"DateIssued": "2013-03-11T04:00:00Z",
"ValidFor": 0,
"entityAspect": {
"entityTypeName": "License:#Volt.Telecom.Licensing.Models",
"entityState": "Added",
"originalValuesMap": {},
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
}
],
"saveOptions": {
"allowConcurrentSaves": false
}
}
Don't think I can get much more vanilla than this. Why might this occur? When I am debugging on the client the state and licenseType navigationProperties are all correct and with the correct values.
I think the issue is that your EF model uses 'Independent Associations' instead of 'Foreign Key Assocations' (foreign key associations are the EF default). We do need to do a better job of documenting this assumption.
The reason for this requirement, which can be bypassed but with a substantial loss of functionality, is that the existence of foreign keys on the client is what allows breeze to automatically fix up relationships between entities that might be queried separately.
See the following MSDN article for more background: foreign-keys-in-the-entity-framework

how to select data from multiple table using multiple dropdown and insert the selected values in one table in database in mvc

Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Lecture timetable)
{
Lecture t = new Lecture();
ViewBag.SId = new SelectList(db.Sections, "Id", "SectionName");
ViewBag.CId = new SelectList(db.Course, "Id", "CourseName");
ViewBag.FId = new SelectList(db.Faculty, "Id", "FacultyName");
if (ModelState.IsValid)
{
db.TimeTable.Add(timetable);
db.SaveChanges();
return RedirectToAction("Create");
}
return View(timetable);
}
Model:
[Table("Lecture")]
public class Lecture
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Terms { get; set; }
public string Semester { get; set; }
public int SectionsId { get; set; }
[ForeignKey("SectionsId")]
public Sections Sections { get; set; }
public int CourseId { get; set; }
[ForeignKey("CourseId")]
public Course Course { get; set; }
public string CreditHourTheory { get; set; }
public string CreditHourLab { get; set; }
public int? LabInstructorId { get; set; }
[ForeignKey("LabInstructorId")]
public Faculty Labinstructor { get; set; }
public int FacultyId { get; set; }
[ForeignKey("FacultyId")]
public Faculty Faculty { get; set; }
public int RoomId { get; set; }
[ForeignKey("RoomId")]
public Rooms Rooms { get; set; }
public string Day { get; set; }
public DateTime Date { get; set; }
public TimeSpan TimeStart { get; set; }
public TimeSpan TimeEnd { get; set; }
}
View:
#Html.DropDownList("SId", null, String.Empty, new { #class = "form-control", #required = "" })
#Html.DropDownList("CId", null , String.Empty, new { #class = "form-control select-section", #required = "" })
#Html.DropDownList("FId", null , String.Empty, new { #class = "form-control select-section", #required = "" })
This is the form with dropdown i want to select these values and after clicking the create button the selected values should be submitted in the table "Lecture" in database
i am getting some error in inserting the selected value in database. Kindly provide me a better solution for this problem. the values in the dropdown are coming from the database from different tables.
The Problem in your another function Create with attribute [HttpGet] (or without any attributes, by default [httpGet]).
Variables in ViewBag must be named as well as members of the class Lecture SectionsId, CourseId, FacultyId.
And you should make redirect to Edit Action.
So,
Controller:
public ActionResult Create()
{
ViewBag.SectionsId = new SelectList(db.Sections, "Id", "SectionName");
ViewBag.CourseId = new SelectList(db.Course, "Id", "CourseName");
ViewBag.FacultyId = new SelectList(db.Faculty, "Id", "FacultyName");
return View(new Lecture());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Lecture timetable)
{
ViewBag.SectionsId = new SelectList(db.Sections, "Id", "SectionName");
ViewBag.CourseId = new SelectList(db.Course, "Id", "CourseName");
ViewBag.FacultyId = new SelectList(db.Faculty, "Id", "FacultyName");
if (ModelState.IsValid)
{
db.TimeTable.Add(timetable);
db.SaveChanges();
return RedirectToAction("Edit");
}
return View(timetable);
}
View:
#Html.DropDownList("SectionsId", null, htmlAttributes: new {#id = "SectionsId", #class = "form-control"})
#Html.DropDownList("CourseId", null, htmlAttributes: new {#id = "CourseId", #class = "form-control"})
#Html.DropDownList("FacultyId", null, htmlAttributes: new {#id = "FacultyId", #class = "form-control"})

Resources