Key data annotation not working when assigned to a separate partial class in my razor web app using efcore .netcore - data-annotations

I am developing an application in razor web apps (asp.netcore) and scaffolding db tables using efcore.
I performed a db-scaffold on my OnlineForms data table, which created my OnlineForms.cs Class. When i directly put the [key] attribute on top of the formid property in this class, I can save to the data table without any issues.
But when I move the [key] data annotation into the partial class OnlineFormsValidation, which references OnlineForms, through the [ModelMetadataType] attribute, and I try to save data; I get the error: "The entity type 'OnlineForm' requires a primary key to be defined."
The Required annotations work properly from inside OnlineFormsValidation class, but the [Key] annotation does not.
Thank you in advance. Any help would be greatly appreciated.
OnlineForm.cs:
namespace VehicleTakeHomeApp.Data.Models
{
public partial class OnlineForm {
[Key] <== works if i put it here, but I want to move it to OnlineFormValidation.cs
public int FormId { get; set; }
public string EmployeeId { get; set; }
public string Name { get; set; }
}
}
OnlineFormValidation.cs:
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
namespace VehicleTakeHomeApp.Data.Models
{
[ModelMetadataType(typeof(OnlineFormValidation))]
public partial class OnlineForm
{
}
public class OnlineFormValidation
{
[Key] <== this annotation is not getting picked up, even though the Required annotations below it get picked up.
public int FormId { get; set; }
[Required(ErrorMessage = "Employee ID is required.")]
public string EmployeeId { get; set; }
[Required(ErrorMessage = "Name is required.")]
public string Name { get; set; }
}
}

I had the OnModelCreating method in my dbcontext class commented out. This method contains the HasKey() from the initial db-scaffold.
I uncommented the OnModelCreating method, and now I don't need to add the [Key] annotation, to either class and it works.
It's more of a workaround then a solution, but its works.

Related

How AspNet Identity with my model

I'm trying to go through this tutorial on the External Authentication Services (C#). I need some initial explanations to go forward. Looking inside the default template that ships MVC5, I see this:
// You can add profile data for the user ...
public class ApplicationUser : IdentityUser
{
public string HomeTown { get; set; }
public DateTime? BirthDate { get; set; }
}
What if I want to call it User instead of ApplicationUser? Maybe I want to add a navigation properties so I can establish relationship with my other models? Also when I look at the table, the name is AspNetUsers instead of ApplicationUser. Finally, What if I want to use my own context?
Thanks for helping.
1)What if I want to call it User instead of ApplicationUser?
You can change to any names you want, just make sure to replace ApplicationUser with the name.
2)Maybe I want to add a navigation properties so I can establish
relationship with my other models?
If you have a class call Address, you want to add addressId as a foreign key, see below:
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
}
public class User : IdentityUser
{
public string HomeTown { get; set; }
public DateTime? BirthDate { get; set; }
public int AddressId { get; set; }
[ForeignKey("AddressId")]
public virtual Address Address { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Address> Addresses { get; set; }
}
3)Also when I look at the table, the name is AspNetUsers instead of
ApplicationUser.
ASP.NET Identity is inherited from the The ASP.NET membership system. When you register a new user
using the default template, AspNetUsers and AspNetUserRoles etc.. these tables are created by default.
You can modify these table name by modifying the IdentityModel.cs. For more detail take a look at the following link:
How can I change the table names when using Visual Studio 2013 ASP.NET Identity?
4)What if I want to use my own context?
You can create your own DBContex, MVC 5 allow you to have mutiple DBContext, such as ApplicationDbContext and DataDbContext(custom DbContext).
ApplicationDbContext usually contains ASP.NET Membership data table.
DataDbContext usually contains data tables unrelated to users.
public class Blog
{
public int BlogId { get; set; }
public int Title { get; set; }
}
public class MyDbContext : DbContext
{
public MyDbContext()
: base("DefaultConnection")
{
}
public DbSet<Blog> Blogs { get; set; }
}
Note: You may need to use EF Migrations, see details here :
ASP.Net Identity customizing UserProfile

MVC4 duplicated UserProfile table

In my project I use MVC4 and some external database using Entity as orm.
I decided to use membership given by MVC, so I just changed in default ConnectionString to point to my external db.
Then, when I launch the app first time, few tables were added, so far so good. Now, the problem is , that when I map new created userProfile table into my dataContext model, then I have a conflict, because this table allready exists in accountModel.
Account model and my new generated model are in the same namespace, which I don't wanna change, so what can I do?
here is class generate by ADO entity model using view add tables method:
public partial class UserProfile
{
public UserProfile()
{
this.Predictions = new HashSet<Prediction>();
}
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<Prediction> Predictions { get; set; }
}
and here from membership
[Table("UserProfile")]
public partial class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
both exist in the same name space, and are in conflict.
You can remove the auto generated class and create a partial class to extend the AccountModel UserProfile class instead.
Create a partial class with the same name and same namespace:
public partial class UserProfile
{
public UserProfile()
{
this.Predictions = new HashSet<Prediction>();
}
public virtual ICollection<Prediction> Predictions { get; set; }
}
By doing this, you have the Predictions property into the membership UserProfile class.

MVC 4, Upshot entities cyclic references

I have a DbDataController which delivers a List of Equipment.
public IQueryable<BettrFit.Models.Equipment> GetEquipment() {
var q= DbContext.EquipmentSet.OrderBy(e => e.Name);
return q;
}
In my scaffolded view everything looks ok.
But the Equipment contains a HashSet member of EquipmentType. I want to show this type in my view and also be able to add data to the EquipmentType collection of Equipment (via a multiselect list).
But if I try to include the "EquipmentType" in my linq query it fails during serialisation.
public IQueryable<BettrFit.Models.Equipment> GetEquipment() {
var q= DbContext.EquipmentSet.Include("EquipmentType").OrderBy(e => e.Name);
return q;
}
"Object Graph for Type EquipmentType Contains Cycles and Cannot be Serialized if Reference Tracking is Disabled"
How can I switch on the "backtracking of references"?
Maybe the problem is that the EquipmentType is back-linking through a HashSet? But I do not .include("EquipmentType.Equipment") in my query. So that should be ok.
How is Upshot generating the model? I only find the EquipmentViewModel.js file but this does not contain any model members.
Here are my model classes:
public class Equipment
{
public Equipment()
{
this.Exercise = new HashSet<Exercise>();
this.EquipmentType = new HashSet<EquipmentType>();
this.UserDetails = new HashSet<UserDetails>();
}
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Picture { get; set; }
public string Link { get; set; }
public string Producer { get; set; }
public string Video { get; set; }
public virtual ICollection<EquipmentType> EquipmentType { get; set; }
public virtual ICollection<UserDetails> UserDetails { get; set; }
}
public class EquipmentType
{
public EquipmentType()
{
this.Equipment = new HashSet<Equipment>();
this.UserDetails = new HashSet<UserDetails>();
}
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Equipment> Equipment { get; set; }
public virtual ICollection<UserDetails> UserDetails { get; set; }
}
try decorating one of the navigation properties with [IgnoreDataMember]
[IgnoreDataMember]
public virtual ICollection<Equipment> Equipment { get; set; }
The model generated by upshot can be found on the page itself. In your Index view you will see the UpshotContext HTML helper being used (given that you are using the latest SPA version), in which the dataSource and model type are specified.
When the page is then rendered in the browser, this helper code is replaced with the actual model definition. To see that, view the source code of your page in the browser and search for a <script> tag that starts with upshot.dataSources = upshot.dataSources || {};
Check here for more info about how upshot generates the client side model.
As for the "backtracking of references", I don't know :)
I figured out - partially how to solve the circular reference problem.
I just iterated over my queried collection (with Include() ) and set the backreferences to the parent to NULL. That worked for the serialisation issue which otherwise already breaks on the server.
The only problem now is the update of a data entity - its failing because the arrays of the referenced entitycollection are static...
To solve the cyclic backreference, you can use the IgnoreDataMember attribute. Or you can set the back reference to NULL before returning the data from the DbDataController
I posted a working solution to your problem in a different question, but using Entity Framework Code First.
https://stackoverflow.com/a/10010695/1226140
Here I show how to generate your client-side model manually, allowing to you to map the data however you please

EF Code First: model type is not pluralized in the repository

I have a State model class:
public class State
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
}
And I am trying to create a Repository:
Scaffold Repository State
I've got in generated file:
public IQueryable<State> All
{
get { return context.State; }
}
instead of context.StateS.
Property
public DbSet<State> States { get; set; }
successfully has been added to the DbContext class.
I have no overrided OnModelCreating method.
Sometimes I mention such problem in different projects but can not find a reason.
I know I've had problems with namespace confusion when using the word "State" for my database tables and POCOs. So to make things easier, I rename those to something else, like USState or StateCode. That could be what's going on here for you and the scaffolding.

MvcScaffolding Keeps Pluralize DbSet item name

here is my model classes;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ContactFormWithMultipleCheckboxApp.Models {
public class Product {
public int ProductId { get; set; }
[Required, StringLength(50)]
public string ProductName { get; set; }
public string Description { get; set; }
public virtual ICollection<Message> Messages { get; set; }
}
public class Message {
public int MessageId { get; set; }
public string From { get; set; }
[Required]
//below one is to validate whether the e-mail address is legit or not
[RegularExpression("\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}\b")]
public string Email { get; set; }
[StringLength(100)]
public string Subject { get; set; }
public string Content { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
}
And I have installed MvcScaffolding as nuget package to my app. I am trying to a simple scaffolding with following code;
PM> Scaffold Controller Message
it works and creates my controllers, views and DBContect class. but I have one problem. why does it pluralize my dbset item inside dbcontect class;
public class ContactFormWithMultipleCheckboxAppContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, add the following
// code to the Application_Start method in your Global.asax file.
// Note: this will destroy and re-create your database with every model change.
//
// System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<ContactFormWithMultipleCheckboxApp.Models.ContactFormWithMultipleCheckboxAppContext>());
public DbSet<ContactFormWithMultipleCheckboxApp.Models.Message> Messages { get; set; }
}
as you can see it creates the name as Messages but it uses Message on the other places like view and controller.
What is happening here?
In this blog post about MvcScaffolding 0.9.4, Steve Sanderson writes:
"Based on your feedback, controller
names are now pluralized by default
(e.g., you get PeopleController rather
than PersonController for a model of
type Person, unless you explicitly
enter PersonController as the
controller name when scaffolding)"
So by default (or convention) it pluralizes your names unless you tell it not to. You stated that you did that, and it didn't pluralize your controller or views.
I wonder if you also need to tell EntityFramework not to pluralize. See this post, "How to singularize in EntityFramework" for more details about that.

Resources