I am using an existing database to create an Project Reporting System. And I want the Primary Key, which is the Project id value of the project table to be automatically created and it is not setting a new value, as I have to input the Id, but I don't want the user to do that. Can anyone help me with this problem please?
Patrick
Controller
` //
// GET: /Project/Create
public ActionResult Create()
{
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName");
ViewBag.SubCategoryID = new SelectList(db.pjt_SubCategories, "pjt_SubCat_ID", "SubCatName");
return View();
}
//
// POST: /Project/Create
[HttpPost]
public ActionResult Create(pjt_Projects pjt_projects)
{
if (ModelState.IsValid)
{
pjt_projects.CreationDate = DateTime.Now;
db.pjt_Projects.Add(pjt_projects);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName", pjt_projects.Status);
ViewBag.SubCategoryID = new SelectList(db.pjt_SubCategories, "pjt_SubCat_ID", "SubCatName", pjt_projects.SubCategoryID);
return View(pjt_projects);
}`
Database Table Script
`CREATE TABLE [dbo].[pjt_Projects](
[Pjt_Id] [int] IDENTITY(1,1) NOT NULL,
[ProjectName] [nchar](100) NULL,
[Status] [int] NULL,
[Start_Date] [date] NULL,
[Estimated_End_Date] [date] NULL,
[Documents] [nvarchar](max) NULL,
[Notes] [nvarchar](max) NULL,
[Budget] [smallmoney] NULL,
[Current_Spending] [smallmoney] NULL,
[ProjectOwner] [nvarchar](50) NULL,
[Active] [bit] NULL,
[Actual_End_date] [date] NULL,
[CreationDate] [date] NULL,
[CreatedByEmpNo] [nchar](10) NULL,
[UpdateDate] [date] NULL,
[UpdatedByEmpNo] [nchar](10) NULL,
[SubCategoryID] [int] NULL,`
**Generate Context Db Code**
public int Pjt_Id { get; set; }
public string ProjectName { get; set; }
public Nullable<int> Status { get; set; }
public Nullable<System.DateTime> Start_Date { get; set; }
public Nullable<System.DateTime> Estimated_End_Date { get; set; }
public string Documents { get; set; }
public string Notes { get; set; }
public Nullable<decimal> Budget { get; set; }
public Nullable<decimal> Current_Spending { get; set; }
public string ProjectOwner { get; set; }
public Nullable<bool> Active { get; set; }
public Nullable<System.DateTime> Actual_End_date { get; set; }
public Nullable<System.DateTime> CreationDate { get; set; }
public string CreatedByEmpNo { get; set; }
public Nullable<System.DateTime> UpdateDate { get; set; }
public string UpdatedByEmpNo { get; set; }
public Nullable<int> SubCategoryID { get; set; }
Simply exclude the ID field from the Razor view. (Self explanatory unless you're using EditorForModel, in which case you'd need to modify the Display annotation for the ID field, so that the Razor engine knows to exclude it from the view.)
Once excluded, its value will not get posted back to the server. That way it will get the default value when created in the MVC controller; and the database will auto-generate the new ID.
Related
I am trying to relate my Tables with ForeignKey and PrimaryKey on the other end. But now i will be using a ForeignKey which is not the primary for the said table. I was using [InverseProperty] but i think there's a bug with it since i've been looking around for hours already and all of them says the same thing about it.
Documents Table:
public class Document
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DocumentId { get; set; }
public int ProjectId { get; set; }
public int DepartmentId { get; set; }
public int AuthorId { get; set; }
[NotMapped]
public virtual User Author { get; set; }
}
Users
public class User
{
[Key]
public int UserId { get; set; }
public int AuthUserId { get; set; }
public string DisplayName { get; set; }
[NotMapped]
[ForeignKey("AuthorId")]
public virtual Document Document { get; set; }
}
Context:
modelBuilder.Entity<User>(entity =>
{
entity.HasOne(u => u.Document)
.WithMany("AuthorId");
});
I am trying to use the solution they here, but no luck.
Any help would really be appreciated. Thanks!
But now i will be using a ForeignKey which is not the primary for the said table.
To do this you can use EF Core Alternate Keys feature. But first correct your model class set up as follows: (As you said a User will have multiple Document)
public class Document
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DocumentId { get; set; }
public int ProjectId { get; set; }
public int DepartmentId { get; set; }
public int AuthorId { get; set; }
public User Author { get; set; }
}
public class User
{
[Key]
public int UserId { get; set; }
public int AuthUserId { get; set; }
public string DisplayName { get; set; }
public ICollection<Document> Documents { get; set; }
}
Then in the Fluent API configuration as follows:
modelBuilder.Entity<Document>()
.HasOne(p => p.Author)
.WithMany(b => b.Documents)
.HasForeignKey(p => p.AuthorId)
.HasPrincipalKey(b => b.AuthUserId); // <-- here you are specifying `AuthUserId` as `PrincipalKey` in the relation which is not primary key
I have tried various answers to try and get this fixed. I have tried to do a refresh but with no luck.
All my tables are currently empty. I already have #Html.HiddenFor~ in the view
My controller save action:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "AdminManager")]
public ActionResult Save(Member member)
{
if (!ModelState.IsValid)
{
var viewModel = new MemberFormViewModel
{
Member = member,
Subjects = _context.Subjects.ToList()
};
return View("MemberForm", viewModel);
}
if (member.Id == 0)
_context.Members.Add(member);
else
{
var memberInDb = _context.Members.Single(m => m.Id == member.Id);
Mapper.Map(memberInDb, member);
}
_context.SaveChanges();
return RedirectToAction("Index", "Member");
}
Specifically the source error shown is:
_context.SaveChanges();
It seems that the code errors when adding a member:
_context.Members.Add(member);
Below is my table code:
CREATE TABLE [dbo].[Members] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (255) NOT NULL,
[DateOfBirth] DATETIME NULL,
[Gender] NVARCHAR (MAX) NULL,
[Email] NVARCHAR (MAX) NOT NULL,
[WorkLocation] NVARCHAR (MAX) NOT NULL,
[Address] NVARCHAR (255) NOT NULL,
[ContactNumber] NVARCHAR (MAX) NOT NULL,
[Biography] NVARCHAR (MAX) NULL,
[MoreInfo] NVARCHAR (MAX) NULL,
[SubjectId] INT NOT NULL,
[ReportId] INT NULL,
CONSTRAINT [PK_dbo.Members] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.Members_dbo.Reports_ReportId] FOREIGN KEY ([ReportId])
REFERENCES [dbo].[Reports] ([Id]),
CONSTRAINT [FK_dbo.Members_dbo.Subjects_SubjectId] FOREIGN KEY ([SubjectId])
REFERENCES [dbo].[Subjects] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_SubjectId]
ON [dbo].[Members]([SubjectId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_ReportId]
ON [dbo].[Members]([ReportId] ASC);
Here is my model that was used for the migration:
public class Member
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Display(Name = "Date of birth")]
public DateTime? DateOfBirth { get; set; }
public string Gender { get; set; }
[Required]
public string Email { get; set; }
[Required]
[Display(Name = "Work Location")]
public string WorkLocation { get; set; }
[Required]
[StringLength(255)]
public string Address { get; set; }
[Required]
[Display(Name = "Contact Number")]
public string ContactNumber { get; set; }
public string Biography { get; set; }
[Display(Name = "More Information")]
public string MoreInfo { get; set; }
public Subject Subject { get; set; }
[Required]
[Display(Name = "Subject")]
public int SubjectId { get; set; }
public Report Report { get; set; }
[Key]
[ForeignKey("Report")]
[Display(Name = "Report")]
public int? ReportId { get; set; }
}
I have a base class Person:
[KnownType(typeof(Doctor))]
public abstract class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public DateTime BirthDate { get; set; }
public string Email { get; set; }
public string MobilePhoneNumber { get; set; }
public string HomePhoneNumber { get; set; }
public bool IsGlobal { get; set; }
public bool IsDeleted { get; set; }
public bool IsApproved { get; set; }
public int? FacilityId { get; set; }
public int? AddressId { get; set; }
public virtual FacilityView Facility { get; set; }
public virtual Address Address { get; set; }
public virtual ICollection<Organization> Organizations { get; set; }
public virtual ICollection<TenantEntity> TenantEntities { get; set; }
}
And have nested class Doctor:
public class Doctor : Person
{
public string Speciality { get; set; }
}
Table Person script
CREATE TABLE [core].[Person](
[PersonId] [int] IDENTITY(1,1) NOT NULL,
[Discriminator] [nvarchar](255) NOT NULL,
[FirstName] [nvarchar](255) NOT NULL,
[MiddleName] [nvarchar](255) NULL,
[LastName] [nvarchar](20) NOT NULL,
[Gender] [nvarchar](20) NOT NULL,
[BirthDate] [date] NOT NULL,
[Email] [nvarchar](250) NULL,
[MobilePhoneNumber] [nvarchar](250) NULL,
[HomePhoneNumber] [nvarchar](250) NULL,
[IsGlobal] [bit] NOT NULL,
[IsDeleted] [bit] NOT NULL,
[IsApproved] [bit] NOT NULL,
[FacilityId] [int] NULL,
[AddressId] [int] NULL,
[Speciality] [nvarchar](250) NULL,
And when i try to save new Doctor entity i have an error:
Cannot insert the value NULL into column 'Discriminator'
What i do wrong in this situation?Why EF not save "Doctor" value in Discriminator field?
UPDATE:
part from DBContext:
public DbSet<Person> Persons { get; set; }
#region Person
modelBuilder.Entity<Person>()
.ToTable("Person", "core")
.HasKey(t => t.PersonId);
modelBuilder.Entity<Person>()
.HasOptional(t => t.Facility);
modelBuilder.Entity<Person>()
.HasOptional(t => t.Address);
modelBuilder.Entity<Person>()
.HasMany(x => x.Organizations)
.WithMany()
.Map(x =>
{
x.MapLeftKey("PersonId");
x.MapRightKey("OrganizationId");
x.ToTable("PersonOrganization", "core");
});
modelBuilder.Entity<Person>()
.HasMany(x => x.TenantEntities)
.WithMany()
.Map(x =>
{
x.MapLeftKey("PersonId");
x.MapRightKey("TenantEntityId");
x.ToTable("PersonTenantEntity", "core");
});
#endregion
The default inheritance mapping does not define a discriminator column if only one derived class exists.
Your code will work if you define a second class that derives from Person:
public class Nurse : Person
{
public string Whatever {get;set;}
}
Or add the discriminator explicitly to your model.
modelBuilder.Entity<Doctor>().Map(p => p.Requires("Discriminator").HasValue("Doctor"));
I have a legacy SQL database that has a linked table to store specifications for order lines. The application designers use an image field in SQL to store the text as binary data. I mocked up an example below:
public class OrderLine
{
public int ID { get; set; }
public int OrderID { get; set; }
public int LineNo { get; set; }
public string Product { get; set; }
public decimal Quantity { get; set; }
public decimal UnitPrice { get; set; }
public string Status { get; set; }
}
public class OrderLineSpecifications
{
public int ID { get; set; }
public int OrderID { get; set; }
public int OrderLineNo { get; set; }
public Image Bits { get; set; } // <--- This Line
public int Bit_Length { get; set; }
}
SQL Table Definition
[ID] [int] IDENTITY(1,1) NOT NULL,
[OrderID] [varchar](15) NOT NULL,
[OrderLineNo] [smallint] NOT NULL,
[Bits] [image] NULL,
[Bit_Length] [int] NOT NULL
Currently I have to use SQL with
cast(cast(Bits as varbinary(max)) as varchar(max))
to extract the text and then perform the reverse to return it to the database. Is it possible to have the conversion done in EF? Perhaps at the property level { get; set;} ?
The solution was easier than I thought. I changed what was identified as an Image in SQL to a byte array (byte[]) and created a property (Specs) that processed the BITS values. Entity Framework was happy and it works in both directions. Surprisingly easy.
public virtual byte[] BITS { get; set; }
public virtual int BITS_LENGTH { get; set; }
[NotMapped]
public virtual string Specs
{
get
{
UTF8Encoding enc = new UTF8Encoding();
string str = enc.GetString(BITS);
return str;
}
set
{
UTF8Encoding encoding = new UTF8Encoding();
BITS = encoding.GetBytes(value);
}
}
How do I map these existing tables to the classes below?
I have the following tables:
CREATE TABLE dbo.UserContact (
UserContactId int NOT NULL IDENTITY (1, 1),
UserId int NOT NULL,
ContactId int NOT NULL,
UserContactTypeId int NOT NULL,
FromDt datetime NULL,
ThruDt datetime NULL,
CreateDt datetime NOT NULL,
UpdateDt datetime NULL,
IsDeleted bit NULL,
CanSolicit bit NOT NULL
)
CREATE TABLE dbo.Contact (
ContactId int NOT NULL IDENTITY (1, 1),
CreateDt datetime NOT NULL,
UpdateDt datetime NULL
)
CREATE TABLE dbo.Electronic (
ContactId int NOT NULL,
URL nvarchar(512) NOT NULL,
ElectronicType smallint NULL
)
CREATE TABLE dbo.Phone (
ContactId int NOT NULL,
AreaCode nchar(3) NOT NULL,
PhoneNb nchar(7) NOT NULL,
Extension nchar(6) NULL,
PhoneType smallint NULL
)
CREATE TABLE dbo.Postal
(
ContactId int NOT NULL,
Street nvarchar(256) NOT NULL,
Specifier nvarchar(256) NULL,
GeocodeId int NULL
)
The tables Electronic, Phone and Postal are in a one-to-one relationship with Contact. The table UserContact is in a many-to-one with Contact; UserContact is an association table between User and Contact.
I also have the following classes:
public class Electronic : IntegerKeyEntity
{
public virtual ContactId { get; set; }
public virtual DateTime CreateDt { get; set; }
public virtual DateTime? UpdateDt { get; set; }
public string Url { get; set; }
public ElectronicType Type { get; set; }
}
public class Postal : IntegerKeyEntity
{
public virtual ContactId { get; set; }
public virtual DateTime CreateDt { get; set; }
public virtual DateTime? UpdateDt { get; set; }
public string Street { get; set; }
public string Specifier { get; set; }
public Geocode Geocode { get; set; }
}
public class Phone : IntegerKeyEntity
{
public virtual ContactId { get; set; }
public virtual DateTime CreateDt { get; set; }
public virtual DateTime? UpdateDt { get; set; }
public string AreaCode { get; set; }
public string PhoneNb { get; set; }
public string Extension { get; set; }
public PhoneType Type { get; set; }
}
public class UserContact : IntegerKeyEntity
{
private ICollection<Electronic> electronics = new HashSet<Electronic>();
private ICollection<Phone> phones = new HashSet<Phone>();
private ICollection<Postal> postals = new HashSet<Postal>();
// props
public virtual IEnumerable<Electronic> Electronics { get { return electronics; } }
public virtual IEnumerable<Phone> Phones { get { return phones; } }
public virtual IEnumerable<Postal> Postals { get { return postals; } }
}
So, I do I get from the four Contact tables (parent and child) down to the three classes? And, how do I map those three classes to the UserContact table. I'm assuming I can have three ILists, one for each class.
I think you're modeling this incorrectly. It appears to me that Electronic, Phone, and Postal extend (inherit from) Contact and this should be expressed in your domain model. Those classes are not related to Contact by one-to-one, they are concrete types that extend the abstract Contact type. If you model it this way you can map Contact using table-per-subclass inheritance mapping.
User would then have a many-to-many-relationship with Contact, and the user's Contacts collection would contain Contacts of any type.
Personally I would put all the Contact types into one table and use the simpler table-per-class mapping.