I'm trying to build an application in Mvc with Individual User Accounts, and I'm trying to connect the automatically generated database with my own context.
The problem I have when I trying to create a view of my Create method I get this errormessage:
There was an error running the selected code generator: 'Unable to
retrieve metadata for 'Projekt_Dejtingsida.Models.Messages' is not
valid. The navigation property 'ApplicationUser' was not found on the
dependent type 'Projekt_Dejtsida.Models.Messages'. The Name value
should be a valid navigation property name.
Please help a beginner out!
Here are the models I'm using:
I have already tried the protected override void OnModelCreating(DbModelBuilder modelBuilder) method, but it didn't work...
public class Messages {
[Key, ForeignKey("ApplicationUser")]
public string Id { get; set; }
[Key]
public int MessageId { get; set; }
public virtual ApplicationUser Sender { get; set; }
public virtual ApplicationUser Receiver { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "You can't send a message without a content")]
[StringLength(300, MinimumLength = 3, ErrorMessage = "Your message should be between 3 and 300 characters")]
public string MessageContent { get; set; }
}
public class FriendRequests {
public string UserId { get; set; }
[Key]
public int RequestId { get; set; }
public virtual ApplicationUser RequestTo { get; set; }
public virtual ApplicationUser RequestFrom { get; set; }
public bool Confirmed { get; set; }
}
public class Profile {
[Key]
public string UserId { get; set; }
public byte[] ProfilePicture { get; set; }
public string Firstname { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public string About { get; set; }
public virtual ICollection<Messages> MyMessages { get; set; }
}
Here is the DbContext:
public class DatesiteContext : DbContext {
public DatesiteContext() : base() { }
public DbSet<FriendRequests> Requests { get; set; }
public DbSet<Messages> Messages { get; set; }
public DbSet<Profile> Profiles { get; set; }
}
Here is the MessageController
[Authorize]
public class MessageController : Controller
{
// GET: Message
public ActionResult Index()
{
var db = new DatesiteContext();
var userId = User.Identity.GetUserId();
var msgs = db.Messages.FirstOrDefault(m => m.Id == userId);
return View(new MessageViewModel {
Sender = msgs.Sender,
Receiver = msgs.Receiver,
MessageContent = msgs.MessageContent
});
}
public ActionResult Create(MessageViewModel model) {
DatesiteContext db = new DatesiteContext();
var userId = User.Identity.GetUserId();
var msgs = db.Messages.FirstOrDefault(m => m.Id == userId);
if (msgs == null) {
db.Messages.Add(new Messages {
Id = userId,
Sender = msgs.Sender,
Receiver = msgs.Receiver,
MessageContent = msgs.MessageContent
});
} else {
msgs.Sender = model.Sender;
msgs.Receiver = model.Receiver;
msgs.MessageContent = model.MessageContent;
}
db.SaveChanges();
return RedirectToAction("Index", "Profile");
}
}
Related
I have this classes in Code First asp.net
public class Account
{
[Key]
public int Id { get; set; }
[Column(TypeName = "nvarchar(100)")]
public string AccountTitle { get; set; }
public Classification Classification { get; set; }
}
public class Classification
{
[Key]
public int Id { get; set; }
[Column(TypeName = "nvarchar(100)")]
public string TitleClassification { get; set; }
public ICollection<Account> Accounts { get; set; }
}
public class ClassificationDto
{
public int Id { get; set; }
public string TitleClassification { get; set; }
}
In my Db Context
public DbSet<Account> Accounts { get; set; }
AccountingManager.FindAll is this
public IQueryable<T> FindAll()
{
return context.Set<T>().AsNoTracking().AsQueryable();
}
I am trying to get just the "Classification" which is just 3 but I am getting the "Account" that is associated with it too with this code:
[HttpGet]
[Route("get-classification")]
[Authorize]
public async Task<IActionResult> GetAccountClassification()
{
List<ClassificationDto> classificationList = new List<ClassificationDto>();
var accountingManager = new AccountingManager(context);
var list = accountingManager.FindAll();
classificationList = await list.Select(s => new ClassificationDto
{
Id = s.Classification.Id,
TitleClassification = s.Classification.TitleClassification,
}).ToListAsync();
return StatusCode(StatusCodes.Status200OK, classificationList);
}
This is how it is in my table
If you want to get all rows from Classification table,
add public DbSet<Classification> Classifications { get; set;} property to your DbContext class. And then implement similar to FindAll() method:
return context.Classifications.AsNoTracking().ToList()
I am using code first migrations for creating entities. My entities look like that:
public class User
{
private string userWholeName = string.Empty;
private ICollection<UsersInRoles> usersInRoles;
public User()
{
this.UserId = Guid.NewGuid();
this.usersInRoles = new System.Collections.Generic.HashSet<UsersInRoles>();
}
[Key]
public Guid UserId { get; set; }
//TODO: check for resource names and for all models
[Required(AllowEmptyStrings = false, ErrorMessage = null)]
public string UserName { get; set; }
[Required(AllowEmptyStrings = false)]
[MaxLength(30)]
public string Password { get; set; }
public virtual ICollection<UsersInRoles> UsersInRoles
{
get { return this.usersInRoles; }
set { this.usersInRoles = value; }
}
}
My UsersInRolesClass:
public class UsersInRoles
{
public UsersInRoles()
{
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UsersInRolesId { get; set; }
public Guid UserId { get; set; }
public int RoleId { get; set; }
public virtual Role Role { get; set; }
public virtual User User { get; set; }
}
My Role class:
public class Role : Interfaces.IRole
{
private ICollection<UsersInRoles> usersInRoles;
public Role()
{
this.usersInRoles = new HashSet<UsersInRoles>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RoleId { get; set; }
[Required]
public string RoleName { get; set; }
public string RoleDescription { get; set; }
public virtual ICollection<UsersInRoles> UsersInRoles
{
get
{
return this.usersInRoles;
}
set
{
this.usersInRoles = value;
}
}
}
So those are my db entities. I am trying to map them to:
public class UserDTO
{
//other properties same as in User entity
IList<RoleDTO> Roles { get; set; }
}
public class RoleDTO
{
int RoleId { get; set; }
string RoleName { get; set; }
}
Every property is mapped, but Roles are not. I am trying this:
Mapper.Initialize(cfg => cfg.CreateMap<UserDTO, User>().ForMember(dest => dest.UsersInRoles, opt => opt.ResolveUsing(c=>c.Roles.Select(f=>new UsersInRoles() { Role = new Role() { RoleId = f.RoleId,RoleName = f.RoleName}, RoleId = f.RoleId,UserId = c.UserId }))));
Any Ideas ?
Sql Tables Here
public partial class Users
{
public Users()
{
UsersRelationFollower = new HashSet<UsersRelation>();
UsersRelationFollowing = new HashSet<UsersRelation>();
Vote = new HashSet<Vote>();
VoteRating = new HashSet<VoteRating>();
}
public string Id { get; set; }
public string UserType { get; set; }
public string UserName { get; set; }
public string Mail { get; set; }
public string ImageUrl { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? ModifyDate { get; set; }
public bool State { get; set; }
public virtual UserPasswords UserPasswords { get; set; }
public virtual CorporateProperty CorporateProperty { get; set; }
public virtual UserProperty UserProperty { get; set; }
public virtual ICollection<UsersRelation> UsersRelationFollower { get; set; }
public virtual ICollection<UsersRelation> UsersRelationFollowing { get; set; }
public virtual ICollection<Vote> Vote { get; set; }
public virtual ICollection<VoteRating> VoteRating { get; set; }
}
public partial class UserProperty
{
public string Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDay { get; set; }
public string Gender { get; set; }
public string Locale { get; set; }
public string PhoneNumber { get; set; }
public bool State { get; set; }
public virtual Users IdNavigation { get; set; }
}
public partial class CorporateProperty
{
public string Id { get; set; }
public string OrganisationName { get; set; }
public string Website { get; set; }
public bool State { get; set; }
public virtual Users IdNavigation { get; set; }
}
UserControllerClass
// GET: api/Users/5
[HttpGet("{id}")]
public async Task<IActionResult> GetUsers([FromRoute] string id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var users = await _context.Users.SingleOrDefaultAsync(m => m.Id == id);
if (users == null)
{
return NotFound();
}
return Ok(users);
}
My problem is exactly this; User information is coming but the password and property table information is not coming.
How to modify the following line solves my problem?
var users = await _context.Users.SingleOrDefaultAsync(m => m.Id == id);
based on your code this would also hydrate your CorporateProperty & UseProperty objects, etc.
var user = await _context.Users.Include(user => user.UserProperty).Include
(user => user.CorporateProperty).SingleOrDefaultAsync(user => user.Id == id);
lazy loading doesn't exist yet so you have Eager Loading to play with for now.
Surprised you didn't roll with Identity since this all of this would have been taken care for you especially Passwords... Hope you aren't rolling your own hash for that..
Just add in the custom class / collection objects you need.
you can also check out this link
https://learn.microsoft.com/en-us/ef/core/querying/related-data
I'm having the strangest problem and I know it's because I'm missing something obvious because this set up works fine when I save data and even pull it down.
My app is set up like so ....
WebUI depends on Business Layer .. Business Layer depends on Data Layer (which is where I'm actually pulling the data). The Business Layer does all the "work".
This is where everything dies (Null Exception, Object Reference not set) as soon as I assign something to userInfo.userData.avatarFilepath (which is not null).
namespace pgl.businesslayer
{
public class userCtx
{
private pgl.datalayer.Concrete.EFDbContext context = new pgl.datalayer.Concrete.EFDbContext();
private pgl.datalayer.Concrete.EFUserContext userContext = new pgl.datalayer.Concrete.EFUserContext();
private pgl.datalayer.Concrete.EFDbCompany companyContext = new pgl.datalayer.Concrete.EFDbCompany();
public ViewModels.UserInfo getUserById(int userId)
{
ViewModels.UserInfo userInfo = new ViewModels.UserInfo();
pgl.datalayer.Dtos.pglUserDTO userDL = userContext.getUserByUserId(userId);
userInfo.userData.avatarFilepath = userDL.avatarFilepath;
userInfo.userData.createdBy = userDL.createdBy;
userInfo.userData.createdDate = userDL.createdDate;
userInfo.userData.email = userDL.email;
userInfo.userData.firstName = userDL.firstName;
userInfo.userData.lastName = userDL.lastName;
etc...
}
ViewModels.UserInfo looks like this...
namespace pgl.businesslayer.ViewModels
{
public class UserInfo
{
// user info
public pgl.businesslayer.Dto.pglUser userData { get; set; }
// salon info
public List<pglSalon> salonsData { get; set; }
// company info
public pglCompany companyData { get; set; }
}
pglUser in the business layer looks like this and is just a POCO
namespace pgl.businesslayer.Dto
{
public class pglUser
{
public int userId { get; set; }
public int companyId { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public string username { get; set; }
public byte[] passwordSalt { get; set; }
public byte[] passwordKey { get; set; }
public DateTime createdDate { get; set; }
public int createdBy { get; set; }
public bool passwordResetRequired { get; set; }
public string passwordHash { get; set; }
public string tempPassword { get; set; }
public string userType { get; set; }
public string avatarFilepath { get; set; }
public string timeZone { get; set; }
}
}
And in userContext this is how I am pulling the user data...
public pgl.datalayer.Dtos.pglUserDTO getUserByUserId(int userId)
{
var getUser = (from u in context.pglUser
select new pgl.datalayer.Dtos.pglUserDTO
{
username = u.username,
companyId = u.companyId,
userId = u.userId,
userType = u.userType,
firstName = u.firstName,
lastName = u.lastName,
email = u.email,
createdDate = u.createdDate,
createdBy = u.createdBy,
passwordResetRequired = u.passwordResetRequired,
tempPassword = u.tempPassword,
avatarFilepath = u.avatarFilepath,
timeZone = u.timeZone
}).Where(u => u.userId == userId).FirstOrDefault();
return getUser;
}
pgl.datalayer.Dtos.pglUserDTO looks like this...
namespace pgl.datalayer.Dtos
{
public class pglUserDTO
{
public int userId { get; set; }
public int companyId { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public string username { get; set; }
public byte[] passwordSalt { get; set; }
public byte[] passwordKey { get; set; }
public DateTime createdDate { get; set; }
public int createdBy { get; set; }
public bool passwordResetRequired { get; set; }
public string passwordHash { get; set; }
public string tempPassword { get; set; }
public string userType { get; set; }
public string avatarFilepath { get; set; }
public string timeZone { get; set; }
}
}
Even if I assign userInfo.userData.avatarFilepath = "WHATUP!!!" it throws the same error. This has got to be something stupid and simple. I can save data with no problem and when I debug I can see that it is actually pulling the correct user ID and it's associated data. It's just that pgl.businesslayer.ViewModels.UserInfo seems to be un-instantiated. I'm at a loss. I can provide more info... and keep in mind I'm kind of at my wits end so I tried doing weird things like adding (probably) unnecessary DTOs. Any ideas?
You don't appear to be creating the userData object anywhere. When you create a new instance of UserInfo, or in its constructor, try adding:
userData = new pgl.businesslayer.Dto.pglUser();
Or alternatively:
ViewModels.UserInfo userInfo = new ViewModels.UserInfo();
pgl.datalayer.Dtos.pglUserDTO userDL = userContext.getUserByUserId(userId);
userInfo.userData = new pgl.businesslayer.Dto.pglUser {
avatarFilepath = userDL.avatarFilepath,
createdBy = userDL.createdBy,
createdDate = userDL.createdDate,
email = userDL.email,
firstName = userDL.firstName,
lastName = userDL.lastName
};
If you always want to initialise UserInfo with an empty userData member, you could include the creation within the constructor:
namespace pgl.businesslayer.ViewModels
{
public class UserInfo
{
// Default constructor
public UserInfo()
{
userData = new pgl.businesslayer.Dto.pglUser();
}
// user info
public pgl.businesslayer.Dto.pglUser userData { get; set; }
// salon info
public List<pglSalon> salonsData { get; set; }
// company info
public pglCompany companyData { get; set; }
}
}
I have a function:
public void Add(User user)
{
var id = WebSecurity.CurrentUserId;
//add id to FK CUserID
context.User.Add(user);
}
I'm adding user data to database. How to add id value to CUserID?
public class User
{
[key]
public int UserID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string E-mail { get; set; }
public UserProfile CUserID { get; set; }
}
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int CUserId { get; set; }
public string UserName { get; set; }
}
EDIT:
If I try do:
user.CUserId = id;
I get an error:
Cannot implicitly convert type 'int' to 'Project.Models.UserProfile'
Change the User class:
public class User
{
[key]
int UserID { get; set; }
string Name { get; set; }
string Surname { get; set; }
string E-mail { get; set; }
[ForeignKey("UserProfile)]
int CUserID { get; set; }
virtual UserProfile UserProfile { get; set; ]
}
Now you can set the ID value and entity framework will get the matching UserProfile when you save changes.
Going on what you've described in your question, try this:
public void Add(User user)
{
using (var context = new MyDbContext())
{
var currentUser = context.UserProfile.Single(
u => u.UserName == System.Web.HttpContext.Current.User.Identity.Name);
var newUser = new User();
newUser.Name = user.Name;
newUser.Surname = user.Surname;
newUser.Email = user.Email;
newUser.CUserID = currentUser.CUserId;
context.User.Add(newUser);
context.SaveChanges();
}
}