Ok so I have a relationship between the ApplicationUser and QuestionResults, my models are as below, the userId nor the UserName is retrieved, but I really need the UserId setup as a foreignKey on the QuestionResults entity.
Any help is much appreciated the error that I am receiving is as below:
An exception of type 'System.NullReferenceException' occurred in STRA.dll but was not handled in user code
Additional information: Object reference not set to an instance of an object.
on these lines of code:
qr.User.Id = User.Identity.GetUserId();
qr.User.UserName = User.Identity.GetUserName();
Models
public class QuestionResult
{
public QuestionResult()
{
DateCreated = DateTime.Now;
DateModified = DateTime.Now;
}
public int Id { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public int QuestionScore { get; set; }
//navigation properties
public virtual ApplicationUser User { get; set; }
//public ICollection<CategoryResult> CategoryResult { get; set; }
//public virtual Category Category { get; set; }
[NotMapped]
public int CategoryId { get; set; }
public virtual Question Question { get; set; }
public int QuestionId { get; set; }
//public virtual Category Category { get; set; }
//public int CategoryId { get; set; }
}
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string Surname { get; set; }
public string Industry { get; set; }
public string GlobalRegion { get; set; }
public string CurrentSituation { get; set; }
public int SalesForceSize { get; set; }
public bool IsVerified { get; set; }
//navigation properties
public virtual ICollection<CategoryResult> CategoryResult { get; set; }
public virtual ICollection<QuestionResult> QuestionResult { get; set; }
//public virtual ICollection<Report> Report { get; set; }
//public virtual ICollection<SurveyResult> SurveyResult { get; set; }
public virtual Organisation Organisation { get; set; }
public int? OrganisationId { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
Your code is equivalent to this::
var user = qr.User;
user.Id = User.Identity.GetUserId();
If the QuestionResult was already linked to a User then you would not be changing which User is linked to the QuestionResult, you would be changing the Id of an existing User - and that is not allowed anyway.
But the QuestionResult is not already linked to a User. qr.User is null - so you get a null reference exception.
In general, life is much easier in Entity Framework if you add the foreign key to your model:
public class QuestionResult
{
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
}
And now you can set the foreign key directly:
qr.UserId = User.Identity.GetUserId();
References:
Why does Entity Framework Reinsert Existing Objects into My Database?
Making Do with Absent Foreign Keys
So, do you wanna make foreing key for userid?
You can do like that:
public int UserRefID { get; set; }
[ForeignKey("UserRefID")]
public xxx UserID { get; set; } //data name like ApplicationUser
And this error appear coz you have some problem about models or data classes.
Set it as a string
Model:
public ApplicationUser User { get; set; }
public string UserId { get; set; }
Controller:
qr.UserId = User.Identity.GetUserId();
And worked perfectly, even created foreign keys, that easy. Thanks so much!
Related
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public string Id { get; set; }
public string Username { get; set; }
public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
public string Role { get; set; }
public Organization Organization { get; set; }
}
public class Organization
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Phone { get; set; }
public string AccessToken { get; set; }
[ForeignKey("User")]
public string UserId { get; set; }
public User User { get; set; }
}
I have the following two tables created with EF code first.
I need to retrieve my User with Org but I don't want Org property to then again include the same User. How can I avoid that, so all I get is the user with the org?
This is the line that's causing me trouble:
return await _context.Users.Include(x => x.Organization).FirstOrDefaultAsync(x => x.Id == id);
I need to retrieve my User with Org but I don't want Org property to then again include the same User.
Either remove the Organization.User navigation property or, if you just want to remove it from a serialized output, decorate the navigation property with JsonIgnore (or similar)
i am designing a system and one of my entity has one to many relation as shown below.
public class Product
{
public int Id { get; set; }
}
public class CompetitorProduct
{
public int Id { get; set; }
public Product Product { get; set; }
}
competitorProduct indicates that product has a equivalent which is sold by different store. should i define one-to-many relation as shown above or below? which one is correct?
public class Product
{
public int Id { get; set; }
public virtual ICollection<CompetitorProduct> CompetitorProducts{ get; set; }
}
public class CompetitorProduct
{
public int Id { get; set; }
}
Assuming it is a one to many relationship (what would happen if a competitor product was competing with more than one of your products for example) you can do both and add in a foreign key as well.
public class Product
{
public int Id { get; set; }
public virtual ICollection<CompetitorProduct> CompetitorProducts { get; set; }
}
public class CompetitorProduct
{
public int Id { get; set; }
public int ProductId { get; set; }
public virtual Product Product { get; set; }
}
You can then set up your relationship using fluent API as so:
modelBuilder.Entity<CompetitorProduct>(entity =>
{
entity.HasOne(e => e.Product)
.WithMany(e => e.CompetitorProducts)
.HasForeignKey(e => e.ProductId)
.HasConstraintName("FK_ComptetitorProduct_Product");
});
This way you can access the competitor products from the product and the product from the competitor products.
Here is a quick example of a ecommerce site I have worked on and how we did table relations.
I removed a bunch of the fields so you can see what you really need. Once to make relations and run Add-Migration EF will handle the FK constraints for you as long as you identified them in models like how I have below.
public class ApplicationUser : IdentityUser
{
public ApplicationUser()
{
Active = true;
CreateDateTimeUtc = DateTime.UtcNow;
ModifiedDateTimeUtc = DateTime.UtcNow;
}
[StringLength(500)]
public string FirstName { get; set; }
[StringLength(500)]
public string LastName { get; set; }
[StringLength(1000)]
public string Address { get; set; }
[StringLength(100)]
public string Unit { get; set; }
[StringLength(250)]
public string City { get; set; }
[StringLength(25)]
public string State { get; set; }
[StringLength(20)]
public string ZipCode { get; set; }
//This will give access to a list of child carts a user could have
[Index]
public bool Active { get; set; }
public virtual ICollection<Cart> Carts { get; set; }
// Account Profile Image
public byte[] ProfileImage { get; set; }
[StringLength(500)]
public string ProfileFilename { get; set; }
[StringLength(100)]
public string ProfileMimeType { get; set; }
}
[Table("Cart", Schema = "dbo")]
public class Cart : AbstractTable
{
public Cart()
{
IsComplete = false;
}
//This create relation to user table where I can get one unique user.
[StringLength(128)]
[ForeignKey("ApplicationUser")]
public string UserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
//These link us to child tables of Cart where we can get a LIST of the items below
public virtual ICollection<CartCategory> CartCategories { get; set; }
public virtual ICollection<CartItem> CartItems { get; set; }
// Marked when a payment/receipt is generated based off of this cart
public bool IsComplete { get; set; }
}
[Table("CartItem", Schema = "dbo")]
public class CartItem : AbstractTable
{
//This will return one unique cart id and let us access it as the parent record
[ForeignKey("Cart")]
public Guid CartId { get; set; }
public virtual Cart Cart { get; set; }
// Signifies if this was paid for in a receipt
public bool IsComplete { get; set; }
public virtual ICollection<CartItemCustomField> CustomFields { get; set; }
}
I am creating a table such as this:
public class Team
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string CaptainId { get; set; }
public string CoCaptainId { get; set; }
public string ContactDetails { get; set; }
}
Then I have a table such as this:
public class TeamMember
{
public string Id { get; set; }
public string Description { get; set; }
public string GameDisplayName { get; set; }
public DateTime Joined { get; set; }
public string TeamId { get; set; }
}
I have 2 questions that I do not understand around EF 6 and MVC5.
1) How do I reference my Id field in Team table. Do I set TeamId inside TeamMember as a string or as a Guid? I understand I will need to set the attribute [ForeignKey("Team")] however I still do not understand how to properly reference to it in the code because whenever I need to do any type of comparison, I always have to type .ToString() on the Guid to be able to get the value to compare against another string value.
2) My TeamMember also has an Id, and this Id references User in Identity framework. How should I reference that one, the Id is meant to be a foreign key that references the Id in User table, but I do not know how to properly reference that one either, is it string like I did it or is it Guid or something else?
EDIT:
public class Team
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid CaptainId { get; set; }
public Guid CoCaptainId { get; set; }
}
public class TeamMember
{
public Guid MemberId { get; set; }
public string TeamId { get; set; }
public virtual Team Team { get; set; }
public virtual Member Member { get; set; }
}
public class Member : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string About { get; set; }
public string Alias { get; set; }
public string CustomUrl { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<Member> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<Member>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Team> Teams { get; set; }
public DbSet<TeamMember> TeamMembers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUserClaim>().ToTable("MemberClaim");
modelBuilder.Entity<IdentityUserRole>().ToTable("MemberRole");
modelBuilder.Entity<IdentityUserLogin>().ToTable("MemberLogin");
modelBuilder.Entity<IdentityRole>().ToTable("Role");
modelBuilder.Entity<Member>().ToTable("Member");
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Error that I get:
var user = new Member { UserName = model.Email, Email = model.Email, CustomUrl = model.CustomUrl, Alias = model.Alias};
var team = new Team {CaptainId = user.Id, Created = currentTime, IsSingleMember = true};
CaptainId = user.Id gives an error:
Cannot convert source type 'string' to target type 'System.Guid'
You should use the same type, which is Guid.
public Guid TeamId { get; set; }
Also, you need to keep a virtual Team property of Team type in your TeamMember model. Also typically int or long or Guid are the types used for primary key of a table. string might not be a good idea as you need to execute your custom code to generate a string which does not exist in the table.
This will generate the 2 tables with proper foreign key relationships.
public class Team
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string CaptainId { get; set; }
public string CoCaptainId { get; set; }
public string ContactDetails { get; set; }
}
public class TeamMember
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Description { get; set; }
public string GameDisplayName { get; set; }
public DateTime Joined { get; set; }
public Guid TeamId { get; set; }
public virtual Team Team { set; get; }
}
You do not need to do a ToString() conversion now for comparison. You can do YourGuid1==YourGuid2 expression
In my project i need to add Sales leads to the data context. The sales person user adds the leads and I need to send the email to manager for the Lead.
public partial class Lead
{
public Lead()
{
this.LeadActivities = new HashSet<LeadActivity>();
}
public long LeadID { get; set; }
public System.DateTime CreatedAt { get; set; }
public long CompanyID { get; set; }
public long ProductID { get; set; }
public long CreatedByUserID { get; set; }
public string Remarks { get; set; }
public LeadStatusEnum StatusID { get; set; }
public virtual Company Company { get; set; }
public virtual Product Product { get; set; }
public virtual User User { get; set; }
public virtual ICollection<LeadActivity> LeadActivities { get; set; }
}
[Serializable]
public partial class Person
{
public Person()
{
this.Contacts = new HashSet<Contact>();
this.Users = new HashSet<User>();
}
public long PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Designation { get; set; }
public Nullable<int> Gender { get; set; }
public Nullable<int> Title { get; set; }
public int StatusID { get; set; }
public string Thumbnail { get; set; }
public string Email { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
public virtual ICollection<User> Users { get; set; }
}
In the above entity, I have property UserID that is associated to Person table through CreatedByUserID. When I add the new lead, by following code, the User field remains null. Do I need to reconstruct it? if yes then how.
Edit1
Entity Creation is done by following code
Entity = new Model.Lead
{
CreatedAt = DateTime.Now,
CreatedByUserID = SessionManagement.GeneralSession.UserDetail.UserID
};
Entity.CreatedAt = Convert.ToDateTime(txtTimestamp.Value);
Entity.CompanyID = Convert.ToInt64(ddlCompany.SelectedValue);
Entity.CreatedByUserID = Convert.ToInt64(ddlUser.SelectedValue);
Entity.ProductID = Convert.ToInt64(lstProducts.SelectedValue);
Entity.Remarks = txtRemarks.Text;
DataSource.Leads.Add(Entity);
DataSource.SaveChanges();
Virtual lazy loading only works with proxy instances. Since you're explicitly constructing your Lead entity, lazy loading of the User navigation property after inserting the entity will not work.
Instead, you should use the DbSet.Create method to new up an instance of the derived proxy type. Then perform your insert, which will attach to the context, and lazy loading will subsequently work.
Alternatively, you can use your existing POCO, perform the insert and then fetch your inserted entity as its proxy from the DbSet by using the DbSet.Find method.
You should also check and make sure your foreign key id and navigation properties are correctly mapped, since properties CreatedByUserID and User would not be automatically associated by convention.
I have a working model, but have noticed that the relationship has been created twice in the database. Originally, it created two columns in the table, but with the addition of a specified foreign key attribute it has now just the one.
I have an Account class, which has many employers who can use the account. (one to many) Here are the classes:
public class Account
{
public int AccountId { get; set; }
[Required(ErrorMessage = Constants.ValidationMessages.FieldRequired)]
public string Name { get; set; }
public int? PrimaryUserId { get; set; }
[ForeignKey("PrimaryUserId")]
public Employer PrimaryUser { get; set; }
[ForeignKey("EmpAccountId")]
public ICollection<Employer> Employers { get; set; }
}
here is the inherited Employer class
public class Employer : User
{
public Employer()
{
DepartmentsToPost = new Collection<Department>();
Contacts = new Collection<Contact>();
}
[Display(Name = "Workplaces to advertise jobs")]
public virtual ICollection<Department> DepartmentsToPost { get; set; }
public int EmpAccountId { get; set; }
[ForeignKey("EmpAccountId")]
public virtual Account Account { get; set; }
public override string UserType
{
get { return "Employer"; }
}
}
User Table:
UserId
Username
FirstName
Surname
EmpAccountId
Discriminator
Account Table
AccountId
Name
PrimaryUserId
There is one link back to the User table - this is for the PrimaryUser field, and this is correct. There are two other relationships: Account -> Employers. EF has named them Account_Employers and Employer_Account. These are duplicates.
How can I prevent this occuring?
The Employers collection should be decorated with InversePropertyAttribute to point to the navigational property on the other side.
public class Account
{
public int AccountId { get; set; }
[Required(ErrorMessage = Constants.ValidationMessages.FieldRequired)]
public string Name { get; set; }
public int? PrimaryUserId { get; set; }
[ForeignKey("PrimaryUserId")]
public Employer PrimaryUser { get; set; }
[InverseProperty("Account")]
public ICollection<Employer> Employers { get; set; }
}