I went through the Movies tutorial on asp.net, which went fine. Created the application using a local SQL Server instance, database was created flawlessly, and all functionality worked as designed. I created a new, entirely separate application without importing or copying anything from the Movies application. Defined a new model and DBContext, new controller, etc. When I try to execute the application for the same time I get the following error:
The model backing the 'OnlineAppDBContext' context has changed since the >database was created. Consider using Code First Migrations to update the >database (http://go.microsoft.com/fwlink/?LinkId=238269).
I went through the exercise of adding the migrations and noticed in the init migration I added that it is referencing the Movie model and database:
public override void Up()
{
CreateTable(
"dbo.OnlineApps",
c => new
{
ID = c.Int(nullable: false, identity: true),
FirstName = c.String(),
MiddleInitial = c.String(),
LastName = c.String(),
PreviousFullName = c.String(),
Gender = c.String(),
BirthDate = c.DateTime(nullable: false),
SSN = c.String(),
Tobacco = c.Boolean(nullable: false),
Address1 = c.String(),
Address2 = c.String(),
City = c.String(),
County = c.String(),
State = c.String(),
ZipCode = c.String(),
HomePhone = c.String(),
WorkPhone = c.String(),
CellPhone = c.String(),
Email = c.String(),
PCPChoice = c.String(),
})
.PrimaryKey(t => t.ID);
DropTable("dbo.Movies");
}
public override void Down()
{
CreateTable(
"dbo.Movies",
c => new
{
ID = c.Int(nullable: false, identity: true),
Title = c.String(maxLength: 60),
ReleaseDate = c.DateTime(nullable: false),
Genre = c.String(nullable: false, maxLength: 30),
Price = c.Decimal(nullable: false, precision: 18, scale: 2),
Rating = c.String(maxLength: 5),
})
.PrimaryKey(t => t.ID);
DropTable("dbo.OnlineApps");
}
The Up() method looks to do the correct table structure for my new model, but then tries to drop dbo.Movies. The Down() method table structure is based on the Movie model, but I have no idea how it is aware of that, and then tries to drop the dbo.OnlineApps table.
I searched through all files in the new application and just for fun rebooted the entire machine, but still having the same problem. Any ideas?
EDIT On a hunch I created a new database on my server. The movies application used a database called 'Sandbox'. I created an 'OnlineApplication' database on the same server, changed the connection string in the new application, and when it ran the objects were created without error. While this got me through the issue I'm not overly satisfied with the answer. Why would the connection string convey any relation to a model from a completely different application? Is this stored somewhere it can be edited/deleted? Can I not define multiple contexts to the same database?
Related
I'm trying to get a certain amount of animals that have the most comments once I try to delete one of them so I'm getting an error of:
SqlException: The DELETE statement conflicted with the REFERENCE constraint "FK__Comments__Animal__2EDAF651". The conflict occurred in database "PetShop", table "dbo.Comments", column 'AnimalId'. The statement has been terminated.
I want to make it possible that if I delete then you will move on to the next in line
My Controller for disply:
public async Task<IActionResult> Index()
{
var animal = _context.Animals.Include(c => c.Comments).OrderByDescending(c => c.Comments.Count).Take(2);
return View(await animal.ToListAsync());
}
My Controller for Delete:
public async Task<Animal> DeleteAnimal(int id)
{
var comment = await _context.Comments.FindAsync(id);
_context.Comments.Remove(comment!);
var animal = await _context.Animals.FindAsync(id);
_context.Animals.Remove(animal!);
await _context.SaveChangesAsync();
return animal!;
}
My Context:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Comment>(entity =>
{
entity.HasOne(d => d.Animal)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.AnimalId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK__Comments__Animal__2EDAF651");
});
modelBuilder.Entity<Category>(entity =>
entity.HasData(
new { CategoryId = 1, Name = "Dogs" },
new { CategoryId = 2, Name = "Cats" },
new { CategoryId = 3, Name = "Birds" },
new { CategoryId = 4, Name = "Rabbits" },
new { CategoryId = 5, Name = "Hamsters" }
)
);
modelBuilder.Entity<Animal>(entity =>
{
entity.HasData(
new { AnimalId = 1, Name = "Shoko", BirthDate = DateTime.Now.AddYears(-1).AddMonths(-1).AddDays(-12), Description = "Friendly and loyal", CategoryId = 1, PhotoUrl = "ShokoDog.jpg" },
new { AnimalId = 2, Name = "Bamba", BirthDate = DateTime.Now.AddYears(-2).AddMonths(-2).AddDays(-3), Description = "Furry and neutered", CategoryId = 2, PhotoUrl = "BambaCat.jpg" },
new { AnimalId = 3, Name = "Regev", BirthDate = DateTime.Now.AddYears(-1).AddMonths(-3).AddDays(-3), Description = "Speak", CategoryId = 3, PhotoUrl = "RegevBird.jpg" },
new { AnimalId = 4, Name = "Humi", BirthDate = DateTime.Now.AddYears(-3).AddMonths(-4).AddDays(-7), Description = "Cute and furry", CategoryId = 4, PhotoUrl = "HumiRabbit.jpg" },
new { AnimalId = 5, Name = "Tommy", BirthDate = DateTime.Now.AddYears(-1).AddMonths(-7).AddDays(-9), Description = "Love to play in the facilities", CategoryId = 5, PhotoUrl = "TommyHamster.jpg" });
});
OnModelCreatingPartial(modelBuilder);
}
You want to remove a parent Animal and related child Comments
To expand on Karlis' suggestions:
You have models and context as posted in the question (it's a bit problematic because you say to EF to set null, but the code and DB won't accept null) but you can do:
var a = context.Animals.Include(a => a.Comments).Find(id):
context.Comments.RemoveRange(a.Comments);
context.Animals.Remove(a);
context.SaveChanges();
This explicitly removes the comments then the animal
Change the context to use .OnDelete(DeleteBehavior.ClientCascade) then you can do:
var a = context.Animals.Include(a => a.Comments).Find(id):
context.Animals.Remove(a);
context.SaveChanges();
This causes EF to implicitly remove the comments it knows about when you tell it explicitly to remove the animal
Change the DB's foreign key to do an ON DELETE CASCADE, and change .OnDelete(DeleteBehavior.Cascade) then you can skip downloading the Comments (no include):
var a = context.Animals.Find(id):
context.Animals.Remove(a);
context.SaveChanges();
This causes the DB to remove the comments (EF doesn't know about them) when EF instructs to delete the animal
Broadly speaking, these are in order of "how bad of a mistake could you make" from "not very" to "quite a lot"
The error message reads that you are deleting Animal, which has comments associated. You should do one of the following:
Remove comments associated with a particular Animal before deleting the Animal.
Check EF configuration for cascade on delete
Alter FK to have cascade on delete (it depends on whether you are using a database-first or code-first approach)
I would go for the first approach because cascade on delete may be dangerous and silently remove unintentionally referenced data.
The database is create successfully as well as the tables. However, whether I put the seed code in the configuration file or as a initializer. The tables are never populated with data.
Things I have tried:
1. I have been viewed several posts on stackoverflow comparing my code with solutions to no avail.
2. I changed DropCreateDatabaseIfModelChanges to DropCreateDatabaseAlways, still the same.
3. I have verified all required fields have a value
public class BankAccountInitializer : DropCreateDatabaseAlways<BankAccountContext>
{
protected override void Seed(BankAccountContext context)
{
var bank1 = new Bank(1) { BankName = "Huntington", BankAccounts = new List<BankAccount>() };
context.Banks.Add(bank1);
context.BankAccounts.Add
(
new CheckingAccount(1)
{
BankId = 1,
AccountBalance = 25.00m,
BankAccountName = "Checking Account 1",
DateAdded = DateTime.Now,
RoutingNumber = 00000887,
Owner = "Checking Account Owner 1",
Bank = bank1
}
);
context.BankAccounts.Add
(
new IndividualInvestment(2)
{
BankId = 1,
AccountBalance = 10.00m,
BankAccountName = "Individual Investment 1",
DateAdded = DateTime.Now,
RoutingNumber = 00000887,
Owner = "Individual Investment Owner 1",
Bank = bank1
}
);
context.BankAccounts.Add(
new CorporateInvestment(3)
{
BankId = 1,
AccountBalance = 98.00m,
BankAccountName = "Corporate Investment 1",
DateAdded = DateTime.Now,
RoutingNumber = 00000887,
Owner = "Corporate Investment Owner 1",
Bank = bank1
}
);
base.Seed(context);
}
}
}
At the link below I asked a question about how to ensure a field does not already contain the same value (for example when there is a unique constraint on a field which correctly causes C# to throw an exception when voilated). With the answer I received, it solved that problem but presented another.
Ensuring another record does not already contain the same value for a field
The main issue I now have is that when I create a new View. The validation works as expected. In brief - The system needs to check that the ViewName and ViewPath (route) are both unique so a search of the DB is required.
However, when I edit the view, the validation kicks in again (and it actually should not because obviously the view exists already because you are editing it).
My issue now is how do I customise the remote validation to work differently for edit vs create. While we should not be able to edit the name of a view to match an existing view, we should also not be stopped from saving the current view simply because it is the same as the current view.
Below is my Model (the part that is not (hopefully) generated by a tool :-):
[MetadataType(typeof(IViewMetaData))]
public partial class View : IViewMetaData { }
public interface IViewMetaData
{
[Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")]
[StringLength(50, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")]
[Display(ResourceType = typeof(DALResources), Name = "ViewName")]
[Remote("IsViewNameAvailable", "Validation")]
string ViewName { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")]
[StringLength(400, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")]
[Display(ResourceType = typeof(DALResources), Name = "ViewPath")]
[Remote("IsViewPathAvailable", "Validation")]
string ViewPath { get; set; }
[Display(ResourceType = typeof(DALResources), Name = "ViewContent")]
string ViewContent { get; set; }
}
The part I am having a problem with is the [Remote] validation attribute which is defined below:
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public class ValidationController : Controller
{
private FRCMSV1Entities db = new FRCMSV1Entities();
public JsonResult IsViewNameAvailable(View view)
{
bool isViewNameInvalid = db.View.Any(v => v.ViewName == view.ViewName && v.Id != view.Id);
if (!isViewNameInvalid)
return Json(true, JsonRequestBehavior.AllowGet);
string suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewName);
for (int i = 1; i < 100; i++)
{
string altViewName = view.ViewName + i.ToString();
bool doesAltViewNameExist = db.View.Any(v => v.ViewName == altViewName);
if (!doesAltViewNameExist)
{
suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewName, altViewName);
break;
}
}
return Json(suggestedViewName, JsonRequestBehavior.AllowGet);
}
public JsonResult IsViewPathAvailable(View view)
{
bool doesViewPathExist = db.View.Any(v => v.ViewPath == view.ViewPath && v.Id != view.Id);
if (!doesViewPathExist)
return Json(true, JsonRequestBehavior.AllowGet);
string suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewPath);
for (int i = 1; i < 100; i++)
{
string altViewPath = view.ViewPath + i.ToString();
bool doesAltViewPathExist = db.View.Any(v => v.ViewPath == altViewPath);
if (!doesAltViewPathExist)
{
suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewPath, altViewPath);
break;
}
}
return Json(suggestedViewPath, JsonRequestBehavior.AllowGet);
}
}
The problem is, the validation needs to work the same on both create and edit. It just needs to do an additional check on edit to ensure we are still referring to the same record and if so, then there is no need to show the validation message because there is nothing wrong.
My question is:
1. How do I get this to work as expected.
2. I can see that both methods are pretty much identical, which violates the DRY principle. How can I make this more generic and simplify it. However the first question is really the one I would like answered because there is no point in refactoring something that doesn't work.
For more information, the above code is also an edit of the code at the following link:
https://msdn.microsoft.com/en-us/library/gg508808(VS.98).aspx
Thanks for any help.
You need to add a parameter to pass the ID property of the model as AdditionalFields. Assuming its int Id, then
[Remote("IsViewPathAvailable", "Validation", AdditionalFields = "Id")]
public string ViewName { get; set; }
and the the method should be
public JsonResult IsViewNameAvailable(string viewName, int? id)
Note that in the Edit view, you include a hidden input for the Id property, so its value will be posted back by the jquery.validate remote function.
You can then check if the id parameter is null (i.e. it's new) or has a value (it's existing) and adjust the queries to suit.
bool isViewNameInvalid;
if (id.HasValue)
{
isViewNameInvalid = db.View.Any(v => v.ViewName == viewName && v.Id != id);
}
else
{
isViewNameInvalid = db.View.Any(v => v.ViewName == ViewName);
}
What is currently happening is that the Remote is only posting the value of the ViewName property, and because your parameter is the model, it is initialized with the default id value (0) and your query is translated to Any(v => v.ViewName == viewName && v.Id != 0);
I also recommend using a view model rather that your partial class
Side note: from the code that generates suggestedViewName, your expecting a lot of ViewName with the same value, meaning your possibly making numerous database calls inside you for loop. You could consider using linq .StartsWith() query to get all the records that start with your ViewName value, and then check the in-memory set in your loop.
I am quite new to Asp.net MVC 5 EF6. I am developing the application for Contoso Unversity which is provided by Microsoft on asp.net website. In chapter no.11 Implementing the Inheritance after adding the inheritance and adding the migration through migration command it worked but when i tried to apply the update-database command to the PMC, I faced this error:
Error Number:15248,State:1,Class:11 Either the parameter #objname is
ambiguous or the claimed #objtype (OBJECT) is wrong.
This is the code of My /inheritance migration class.
please guide me to a fix.
namespace ContosoUniversity.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class Inheritance : DbMigration
{
public override void Up()
{
// Drop foreign keys and indexes that point to tables we're going to drop.
DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
DropIndex("dbo.Enrollment", new[] { "StudentID" });
RenameTable(name: "dbo.Instructor", newName: "Person");
AddColumn("dbo.Person", "EnrollmentDate", c => c.DateTime());
AddColumn("dbo.Person", "Discriminator", c => c.String(nullable: false, maxLength: 128, defaultValue: "Instructor"));
AlterColumn("dbo.Person", "HireDate", c => c.DateTime());
AddColumn("dbo.Person", "OldId", c => c.Int(nullable: true));
// Copy existing Student data into new Person table.
Sql("INSERT INTO dbo.Person (LastName, FirstName, HireDate, EnrollmentDate, Discriminator, OldId) SELECT LastName, FirstName, null AS HireDate, EnrollmentDate, 'Student' AS Discriminator, ID AS OldId FROM dbo.Student");
// Fix up existing relationships to match new PK's.
Sql("UPDATE dbo.Enrollment SET StudentId = (SELECT ID FROM dbo.Person WHERE OldId = Enrollment.StudentId AND Discriminator = 'Student')");
// Remove temporary key
DropColumn("dbo.Person", "OldId");
DropTable("dbo.Student");
// Re-create foreign keys and indexes pointing to new table.
AddForeignKey("dbo.Enrollment", "StudentID", "dbo.Person", "ID", cascadeDelete: true);
CreateIndex("dbo.Enrollment", "StudentID");
}
public override void Down()
{
CreateTable(
"dbo.Student",
c => new
{
ID = c.Int(nullable: false, identity: true),
LastName = c.String(nullable: false, maxLength: 20),
FirstName = c.String(nullable: false, maxLength: 20),
EnrollmentDate = c.DateTime(nullable: false),
})
.PrimaryKey(t => t.ID);
AlterColumn("dbo.Person", "HireDate", c => c.DateTime(nullable: false));
DropColumn("dbo.Person", "Discriminator");
DropColumn("dbo.Person", "EnrollmentDate");
RenameTable(name: "dbo.Person", newName: "Instructor");
}
}
}
Consider:
1. Deleting all Migration files in your Migrations folder
2. Renaming your database in the connection string
3. Running PM> add-migration
4. Running PM> update-database
I'm creating a table using a EF migration such as:
this.CreateTable("Message",
c => new
{
Id = c.Long(nullable: false, identity: true, defaultValue: 0),
Subject = c.String(nullable: false, maxLength: 64),
Body = c.String(nullable: false, isMaxLength: true)
})
.PrimaryKey(c => c.Id)
.Index(c => c.Id, unique: true);
How can I define the Id field to be auto_increment? I'm pretty sure it has to be possible, but im just struggling to find out...
Thanks.
Ok, it seems that setting the property "identity: true" in field should be enough but for some reason the field is not defined as IDENTITY(1, 1).
Found a workaround in this post:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/33db16ac-e166-455f-a47b-1e5fe0557979/
And it worked for me like this:
Id = new ColumnModel(PrimitiveTypeKind.Int64) { IsNullable = false, IsIdentity = true },
Now its defining the column as IDENTITY(1, 1)
If you do want to automatically generate it in code, you could skip the annotation on the Id field and do something like below.
public abstract class AbstractContext : DbContext {
/// <summary>
/// Custom processing when saving entities in changetracker
/// </summary>
/// <returns></returns>
public override int SaveChanges()
{
// recommended to explicitly set New Guid for appropriate entities
foreach (var entry in ChangeTracker.Entries<ModelBase>().Where(e => e.State == EntityState.Added) ) {
// only generate if property isn't identity...
Type t = entry.Entity.GetType();
var info = t.GetProperty("Id").GetCustomAttributes(
typeof(DatabaseGeneratedAttribute), true).Cast<DatabaseGeneratedAttribute>().Single();
if (info.DatabaseGeneratedOption != DatabaseGeneratedOption.Identity) {
entry.Entity.Id = Guid.NewGuid(); // now we make it
}
}
return base.SaveChanges();
}
}
For more information check Working with Entity Keys
I got this from the link Which I showed above comment.
I hope this will help to you.