Code-First SQL Server ASP.NET MVC6 - c#

I am a VB.NET programmer, but I am trying to learn C# and MVC in my spare time. I am using ASP.NET MVC 5.1.0.0 and I am trying to do code-First database creation in a local instance of SQL Server.
I was able to get the first database table to update in the database when I ran Update-Database from within the IDE, but when I added a second table that has a PK/FK relationship with the first, I am getting a red line under [ForeignKey] which reads
Does not contain a constructor that takes 1 arguments
I have been searching all over and not getting anywhere. Any suggestions or help would be appreciated. By the way, the first table is a PK/FK relationship to the AspNetUsers table.
public class BuildDatabase : IdentityUser
{
public virtual Companies Companies { get; set; }
public virtual NotaryProfile NotaryProfile { get; set; }
}
public class Companies
{
[Key]
[Column("CompanyID")] // Did this as the database will reflect TableName_ColumnName instead.
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public bool IsActive { get; set; }
public bool IsNotary { get; set; }
public virtual ICollection<NotaryProfile> NotaryProfile { get; set; }
}
public class NotaryProfile
{
[Key]
public int NotaryID { get; set; }
public string NamePrefix { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public string NameSuffix { get; set; }
public bool IsActive { get; set; }
public int DefaultState { get; set; }
public int DefaultCounty { get; set; }
public bool IsSigningAgent { get; set; }
public bool HasABond { get; set; }
public decimal BondAmount { get; set; }
public bool HasEandO { get; set; }
public decimal EandOAmount { get; set; }
public bool ElectronicNotarizationsAllowed { get; set; }
public string ElectronicTechnologyUsed { get; set; }
public string ComissionNumber { get; set; }
public DateTime CommissionIssued { get; set; }
public DateTime CommssionOriginal { get; set; }
public DateTime CommissionExpires { get; set; }
public DateTime CommissionFiledOn { get; set; }
public string SOSAuditNumber { get; set; }
public string CommissionDesc { get; set; }
[Foreignkey("CompanyID")] // Companies.CompanyID = PK
public int CompanyID { get; set; } // PK/FK relationship.
public Companies Companies { get; set; } // Reference to Companies table above.
}
public class SchemaDBContext : IdentityDbContext<BuildDatabase>
{
public SchemaDBContext()
: base("DefaultConnection"){}
public DbSet<Companies> Companies { get; set; }
public DbSet<NotaryProfile> NotaryProfile { get; set; }
}

One of your classes (probably NotaryProfile) needs to reference another object (the foreign key relationship) but there is no constructor in that class that accepts an argument to establish that relationship, e.g.:
public NotaryProfile(int companyId) {
this.companyId = companyId;
}
BTW, a better way to establish that relationship is to use the actual class type rather than the ID, as in:
public class NotaryProfile {
...
public Company Company { get; set; }
// Instead of this:
// public int CompanyID { get; set; } // PK/FK relationship.
...
}
See also:
C# “does not contain a constructor that takes '1' arguments”
Does not contain a constructor that takes 2 arguments

Related

DbUpdateException when adding item to Entity Framework Context

I have the following two classes:
public class Record
{
public int RecordId { get; set; }
public DateTime? InsertDate { get; set; } = DateTime.Now;
public DateTime BookingDate { get; set; }
public string AmountTypeName { get; set; }
public double? Amount { get; set; }
public string BookingAccountID { get; set; }
public string AccountCurrency { get; set; }
public string ClientCurrency { get; set; }
public string AffectsBalance { get; set; }
public double? AmountAccountCurrency { get; set; }
public string AmountClientCurrency { get; set; }
public int UnifiedInstrumentCode { get; set; }
public InstrumentInfo InstrumentInfo { get; set; }
}
public class InstrumentInfo
{
[Key]
public int UnifiedInstrumentCode { get; set; }
public ICollection<Record> Record { get; set; }
public string AssetType { get; set; }
public int UnderlyingInstrumentUic { get; set; }
public string UnderlyingInstrumentSubType { get; set; }
public string InstrumentSymbol { get; set; }
public string InstrumentDescription { get; set; }
public string InstrumentSubType { get; set; }
public string UnderlyingInstrumentAssetType { get; set; }
public string UnderlyingInstrumentDescription { get; set; }
public string UnderlyingInstrumentSymbol { get; set; }
}
that I want to use as my context for EF6.
I defined the context the following way:
public class TransactionsContext: DbContext
{
public DbSet<Record> Records { get; set; }
public DbSet<InstrumentInfo> InstrumentInfos { get; set; }
public TransactionsContext()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<TransactionsContext>(null);
base.OnModelCreating(modelBuilder);
}
}
If I run a test against it that shall add and InstrumentInfo object to the DB
[TestMethod]
public void AddInstrumentInfo_Added_IsTrue()
{
InstrumentInfo info = FakeFactory.GetInstrumentInfo();
using (var ctx = new TransactionsContext())
{
ctx.InstrumentInfos.Add(info);
ctx.SaveChanges();
}
}
I get the following exception:
SqlException: Cannot insert the value NULL into column
'UnifiedInstrumentCode', table
'TransactionsContext.dbo.InstrumentInfoes'; column does not allow
nulls. INSERT fails. The statement has been terminated.
I tried all different scenarios that I found here but I couldn't figure out what I'm doing wrong.
The ultimate goal is that i define my two classes in a way so that a "Record" is linked to the "InstrumentInfo" table via the "UnifiedInstrumentCode" property.
My guess is that my constraints for this two tables are still not correct, but I cant figure out how to define it in EF6 (code first) to get this working.
Adding the annotation [DatabaseGenerated(DatabaseGeneratedOption.None)] to my primary key in InstrumentInfo solved the problem:
public class InstrumentInfo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int UnifiedInstrumentCode { get; set; }
public ICollection<Record> Record { get; set; }
public string AssetType { get; set; }
public int UnderlyingInstrumentUic { get; set; }
public string UnderlyingInstrumentSubType { get; set; }
public string InstrumentSymbol { get; set; }
public string InstrumentDescription { get; set; }
public string InstrumentSubType { get; set; }
public string UnderlyingInstrumentAssetType { get; set; }
public string UnderlyingInstrumentDescription { get; set; }
public string UnderlyingInstrumentSymbol { get; set; }
}
I did not investigate further but my guess is that if a new Record is added, EF initially creates and InstrumentInfo object that has a Null Value for its Primary key which causes the Exception.
I hope it helps if somebody runs into the same problem in future.

Entity Framework code-first generating tables/keys in an unexpected manner

I have many classes representing tables, but three are giving me headaches: Person, Task, and Role, here is their code:
public class Person : BaseModel
{
public int Id { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public string Title { get; set; }
public ICollection<TestEvent> TestEventsLed { get; set; }
public ICollection<TestEvent> TestEventsCreated { get; set; }
public ICollection<Program> ProgramsLed { get; set; }
public ICollection<Task> TasksCreated { get; set; }
public ICollection<PersonalEvent> PersonalEventsCreated { get; set; }
public virtual ICollection<Role> RolesHeld { get; set; }
public virtual ICollection<Task> TasksAssigned { get; set; }
}
public class Role : BaseModel
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Person> PeopleWithThisRole { get; set; }
}
public class Task : BaseModel
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime SuspenseDatetime { get; set; }
public DateTime CreatedDatetime { get; set; }
public int CreatedById { get; set; }
public bool Completed { get; set; }
public bool Archived { get; set; }
public Person CreatedBy { get; set; }
public virtual ICollection<Person> PeopleAssigned { get; set; }
}
What I end up with is mostly what I wanted, except a few hiccups:
Expected: Actual:
- People should have 0 foreign keys, just - People has 1 FK and 1 extra column out of
2 many-to-manys for RolesHeld and nowhere: Task_Id and the FK is for that
TasksAssigned new column referencing Id in Tasks?
- Task should have 1 foreign key for - Task has 2 extra columns out of nowhere
CreatedById linked to a Person called Person_Id and Person_Id1 and then
identical foreign keys attached to them
(and it has the expected CreatedById FK)
- There should be a RolePersons table - This part happened correctly and with the
with 2 FKs to represent the many-to-many correct FKs to represent the many-to-many
- There should be a TaskPersons table - There is no new table at all for this
with 2 FKs to represent the many-to-many
The weird thing is, I did some of these the same way (like the two many-to-many relationships) but then only 1 turned out correctly? Can you see what I did incorrectly?
Sometime default mapping is not what we want, so we have to explicitly say to EF what we need. Just add this method to your DbContext and it works as required:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().HasMany(p => p.TasksAssigned).WithMany(t => t.PeopleAssigned);
modelBuilder.Entity<Person>().HasMany(p => p.TasksCreated).WithRequired(t => t.CreatedBy).WillCascadeOnDelete(false);
}
Entity Framework do something by convention.
Look your Task class and Person class
public class Task : BaseModel
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime SuspenseDatetime { get; set; }
public DateTime CreatedDatetime { get; set; }
public int CreatedById { get; set; }
public bool Completed { get; set; }
public bool Archived { get; set; }
public Person CreatedBy { get; set; }
public virtual ICollection<Person> PeopleAssigned { get; set; }
}
public class Person : BaseModel
{
public int Id { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public string Title { get; set; }
public ICollection<TestEvent> TestEventsLed { get; set; }
public ICollection<TestEvent> TestEventsCreated { get; set; }
public ICollection<Program> ProgramsLed { get; set; }
public ICollection<Task> TasksCreated { get; set; }
public ICollection<PersonalEvent> PersonalEventsCreated { get; set; }
public virtual ICollection<Role> RolesHeld { get; set; }
public virtual ICollection<Task> TasksAssigned { get; set; }
}
In your Task Class you are putting Person object and as well as a collection of Person.That's the thing is the cause of your headache i guess.
If you need many to many relation between them,then you should not put this property inside your Task Class
public Person CreatedById { get; set; }
public Person CreatedBy { get; set; }
Or If you need one to many relation between them,then Remove this property form your Task class
public virtual ICollection<Person> PeopleAssigned { get; set; }

The member with identity 'PmData.SafetyRequirement_Assets' does not exist in the metadata collection.\r\nParameter name: identity

I am trying to update an record in my system. Everything on the model saves great, except any of my many to many type relationships on the form. When I get to those in my model it gives me the error. "The member with identity 'PmData.SafetyRequirement_Assets' does not exist in the metadata collection.\r\nParameter name: identity". I've read over some of the other answers but I do not have any triggers on my database, and I've gone through several changes in my model based on other suggestions and it doesn't seem to change anything. The project is in vNext.
Here is my first model
public partial class Asset : DataModel
{
[Required]
[StringLength(64)]
public string Name { get; set; }
[StringLength(256)]
public string Description { get; set; }
[StringLength(1024)]
public string SystemFunction { get; set; }
[StringLength(2048)]
public string Remarks { get; set; }
public bool IsSystem { get; set; }
public bool IsGrouping { get; set; }
[StringLength(128)]
public string FieldTag { get; set; }
[ForeignKey("Parent")]
public int? ParentId { get; set; }
[ForeignKey("Building")]
public int? BuildingId { get; set; }
public bool IsOperable { get; set; }
public bool IsAvailable { get; set; }
public virtual Asset Parent { get; set; }
public virtual Building Building { get; set; }
public virtual ICollection<Asset> Children { get; set; }
public virtual ICollection<DrawingReference> DrawingReferences { get; set; }
public virtual ICollection<SpecReference> SpecReferences { get; set; }
public virtual ICollection<SafetyRequirement> SafetyRequirements { get; set; }
public virtual ICollection<SupportSystem> SupportSystems { get; set; }
}
The model for one the other table with a many to many.
public partial class SafetyRequirement : DataModel
{
[StringLength(256)]
[Required]
public string Name { get; set; }
[StringLength(2048)]
public string SafetyFunction { get; set; }
[StringLength(2048)]
public string FunctionalRequirements { get; set; }
[StringLength(2048)]
public string SystemBoundary { get; set; }
[StringLength(255)]
public string Reference { get; set; }
[ForeignKey("QualityLevel")]
public int QualityLevelId { get; set; }
public virtual QualityLevel QualityLevel { get; set; }
public virtual ICollection<Asset> Assets { get; set; }
}
The map for the joining table
modelBuilder.Entity<Asset>().HasMany(t => t.SafetyRequirements)
.WithMany(t => t.Assets)
.Map(m =>
{
m.MapRightKey("SafetyRequirementId");
m.MapLeftKey("AssetId");
m.ToTable("AssetSafetyRequirement");
});
Finally here's the area that it fails...
public virtual void SaveAsync(TEntity model)
{
Task.Run(() =>
{
using (
var dbContext =
(TContext)
Activator.CreateInstance(typeof (TContext),
ConfigOptions == null ? ConfigService.ConnectionString : ConfigOptions.ConnectionString))
{
var dbSet = dbContext.Set<TEntity>();
dbSet.Attach(model);
dbContext.Entry(model).State = EntityState.Modified;
dbContext.SaveChanges();
}
});
}
Any information or pointers would be greatly appreciated.
You're trying to use both Fluent API and Data Annotations to define the relationships between your tables. Remove one or the other.

How can I connect the fields of two tables in MVC 5?

I have two models and for which I will create tables through migration and database update. My first model is named Service, and it consists of these fields:
public class Service
{
public int ServiceID { get; set; }
public string ServiceType { get; set; }
public string Category { get; set; }
public string Subcategory { get; set; }
public int Count { get; set; }
}
My second model is called Business, and it has the following fields:
public class Business
{
public int BusinessID { get; set; }
public string BusinessName { get; set; }
public string BusinessWebsite { get; set; }
public string BusinessAddress { get; set; }
public string BusinessCity { get; set; }
public string BusinessState { get; set; }
public string BusinessZip { get; set; }
public string BusinessDescription { get; set; }
[Range(0.0, 5.0)]
public int Rating { get; set; }
public DateTime LastLogIn { get; set; }
// Need to add more fields
}
The point is that I want to add Category and Subcategory fields into my Business model, but the values of Category and Subcategory fields, should be one of the values inside the Service table's values for Category and Subcategory.
Simply, I want to connect those two fields. How can I achieve it? Should I just put a Service property inside the Business model?
Break out a separate entity for "Category" and then use foreign keys:
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class Service
{
...
public virtual Category Category { get; set; }
public virtual Category Subcategory { get; set; }
}
// Do the same when adding category/subcategory fields to `Business`
If you want to ensure that these categories are only tied to Service (and you potentially have other types of categories or something) you can always just make the entity ServiceCategory or something and only create a relationship to it from Service.
You need to separate your break out your database to store lookup table for category and a lookup table for subcategory.
Then you can create:
public class Category {
public int CategoryId { get; set; }
public string Name { get; set; }
}
public class SubCategory {
public int SubCategoryId { get; set; }
public string Name { get; set; }
}
Then change your service class to:
public class Service
{
public int ServiceID { get; set; }
public string ServiceType { get; set; }
public int CategoryId { get; set; }
public int SubcategoryId { get; set; }
public int Count { get; set; }
}
and change your Business class to:
public class Business
{
public int BusinessID { get; set; }
public string BusinessName { get; set; }
public string BusinessWebsite { get; set; }
public string BusinessAddress { get; set; }
public string BusinessCity { get; set; }
public string BusinessState { get; set; }
public string BusinessZip { get; set; }
public string BusinessDescription { get; set; }
public int CategoryId { get; set; }
public int SubCategoryId { get; set; }
[Range(0.0, 5.0)]
public int Rating { get; set; }
public DateTime LastLogIn { get; set; }
// Need to add more fields
}

Error with Entity Framework 4 and MVC 3

I have a database with 3 tables:
Subjects
Members
Topics
Then I added the connection string to web.config and created an EF with the following classes:
namespace MySite.Models
{
public class MySiteDBModel : DbContext
{
public DbSet<Topic> Topics { get; set; }
public DbSet<Subject> Subjects { get; set; }
public DbSet<Member> Members { get; set; }
public DbSet<TopicDataModel> TopicDataModel { get; set; }
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class Topic
{
[Key]
public int TopicID { get; set; }
public int SubID { get; set; }
public int MemberID { get; set; }
public string TDate { get; set; }
public string Title { get; set; }
public string FileName { get; set; }
public int Displays { get; set; }
public string Description { get; set; }
public virtual Subject Subject { get; set; }
public virtual Member Member { get; set; }
public virtual ICollection<TopicView> TopicView { get; set; }
}
public class Subject
{
[Key]
public int SubID { get; set; }
public string SubName { get; set; }
public virtual ICollection<Topic> Topic { get; set; }
}
public class Member
{
[Key]
public int MemberID { get; set; }
public string FLName { get; set; }
public string Email { get; set; }
public string Pwd { get; set; }
public string About { get; set; }
public string Photo { get; set; }
public virtual ICollection<Topic> Topic { get; set; }
}
public class TopicDataModel
{
[Key]
public int TopicID { get; set; }
public string SubName { get; set; }
public string FLName { get; set; }
public string TDate { get; set; }
public string Title { get; set; }
public int Displays { get; set; }
public string Description { get; set; }
}
}
Now when I am trying to query the database with the this code:
public ActionResult Index()
{
var topics = from t in db.Topics
join s in db.Subjects on t.SubID equals s.SubID
join m in db.Members on t.MemberID equals m.MemberID
select new TopicDataModel()
{
TopicID = t.TopicID,
SubName = s.SubName,
FLName = m.FLName,
TDate = t.TDate,
Title = t.Title,
Displays = t.Displays,
Description = t.Description
};
return View(topics.ToList());
}
I got this Error:
The model backing the 'MySiteDBModel' context has changed since the
database was created. Either manually delete/update the database, or
call Database.SetInitializer with an IDatabaseInitializer instance.
For example, the DropCreateDatabaseIfModelChanges strategy will
automatically delete and recreate the database, and optionally seed it
with new data.
Please help me!!!!!!
You need to set some controls on how EF is handling changes to your data model. Julie Lerman has a good blog post on Turning Off Code First Database Initialization Completely.
Also, here is a good overview - Inside Code First Database Initialization

Categories