asp.net MVC User Friends LazyLoad - asp.net-mvc-3

If i try to use code first,
The User Class:
public class User
{
[Key]
public Guid ID { get; set; }
[Required(ErrorMessage = "You must pick a user name")]
[DisplayName("User Name")]
public string Username { get; set; }
[Required]
public string FullName { get; set; }
[Required(ErrorMessage = "You give a valid email address")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
public DateTime CreateAt { get; set; }
public string Image { get; set; }
public bool RemeberMe { get; set; }
public bool Dummy { get; set; }
public virtual ICollection<UserFriend> Friends { get; set; }
}
The UserFriend Class: - hold the relationship between users
public class UserFriend
{
[Key, Column(Order = 0), ForeignKey("User")]
public Guid UserId { get; set; }
public User User { get; set; }
[Key, Column(Order = 1), ForeignKey("Friend")]
public Guid FriendId { get; set; }
public User Friend { get; set; }
public DateTime DateCreated { get; set; }
}
User Repository:
public class UserRepository : IUserRepository
{
public User GetUserByName(string userName)
{
return context.Users.FirstOrDefault(u => u.Username == userName);
}
}
if i try to user this methods:
var userRepo = new UserRepository(new DataContext());
User user = userRepo.GetUserByName(User.Identity.Name);
PROBLEM: user.Friends.first().Friend return null
if i got it right my lazy load not working.
help please...
link to the project - https://github.com/RanDahan/barker

In the contructor of User class you should create new instance of Friends collection
Friends = new HashSet<UserFriend>()
Also, i think navigation properties in UserFirends should also have been declared as virtual.

Related

Linq adding items to list in the query

Good day,
I have one problem. I have three Domain objects
public class User
{
public Guid Id { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[NotMapped]
public List<string> Roles { get; set; }
//nav prop
public List<User_Role> UserRoles { get; set; }
}
public class User_Role
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
//nav prop
public User User { get; set; }
public Guid RoleId { get; set; }
//nav prop
public Role Role { get; set; }
}
public class Role
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<User_Role> UserRoles { get; set; }
}
I want to create DTO object from them
public class ReturnUserDto
{
public Guid Id { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<string> Roles { get; set; }
}
I have created a controller for it
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
public readonly IUserRepository _userRepository;
public readonly IRoleRepository _roleRepository;
public readonly IUserRoleRepository _userRoleRepository
public UserController(IUserRepository userRepository, IRoleRepository IRoleRepository,
IUserRoleRepository userRoleRepository)
{
_userRepository = userRepository;
_roleRepository = IRoleRepository;
_userRoleRepository = userRoleRepository;
}
[HttpGet]
public async Task<IActionResult> GetAllUsersAsync()
{
var users = _userRepository.GetAllAsync();
var usersDto = users.ConvertToDto(unknow arguments)
}
}
And i am trying achieve it by using static DtoConverstion function
It looks like this
public static IEnumerable<ReturnUserDto> ConvertToDto(this IEnumerable<User> users,
IEnumerable<Role> Role)
{
var returnUserDto = (from user in users
select new ReturnUserDto
{
Id = user.Id,
Username = user.Username,
EmailAddress = user.EmailAddress,
Password = user.Password,
FirstName = user.FirstName,
LastName = user.LastName,
Roles = ?(Something like Role.name)
})
}
How do I achieve it? I understand that I need to use user_roles to get roles from it for a specific user, then add it to DtoConvertion function. I am just not sure how to do it.
Can do it multiple ways.One way is to use the Include() and ThenInclude() option
Instead of _userRepository.GetAllAsync(), add a new method which will get the list of Users along with User Roles and its Roles with it. It will be something like
context.Users
.Include(u => u.UserRoles)
.ThenInclude(u => u.Role).ToList()
Then, in the convert method, something like
public static IEnumerable<ReturnUserDto> ConvertToDto(this IEnumerable<User> users)
{
var returnUserDto = (from user in users
select new ReturnUserDto
{
Id = user.Id,
Username = user.Username,
EmailAddress = user.EmailAddress,
Password = user.Password,
FirstName = user.FirstName,
LastName = user.LastName,
Roles = user.UserRoles.Select(s => s.Role.Name).ToList()
})
}
Refer https://learn.microsoft.com/en-us/ef/ef6/querying/related-data if you are not familiar with the Include() method.
Hope this helps.

Invalid Column Name Entity guessing a foreign key that isn't there

I don't really understand what's happening here. From my research I gather that entity is trying to guess the name of a foreign key and it's not there, so it's throwing an "Invalid Column Name" error. The problem is that the model/table in question does not have any foreign keys. So I'm really confused.
Here's the code that throws the error:
foreach (TechnologyProjectPlanModel result in results)
{
//get approvers for plan
int id = result.Id;
try
{
List<ApprovalModel> approvers = db.ApprovalModels.Where(m => m.FormId == result.Id).Select(m => m).ToList(); //ERROR HERE
if (approvers != null)
{
result.Approvers = approvers.ToList();
}
}
catch (Exception e)
{
}
}
Here's the ApprovalModel:
public class ApprovalModel
{
[Key]
public int Id { get; set; }
public int ApprovalProcessId { get; set; }
public int FormId { get; set; }
public int UserId { get; set; }
public bool? Approved { get; set; }
}
And here's the TechnologyProjectPlanModel referenced in the foreach loop:
public class TechnologyProjectPlanModel
{
[Key]
public int Id { get; set; }
public int FormId { get; set; }
public int UserId { get; set; }
public string FormType { get; set; }
public int Status { get; set; }
public int Hidden { get; set; }
public DateTime DateSubmitted { get; set; }
public DateTime DateFinalized { get; set; }
public List<QuoteUploadsModel> Quotes { get; set; }
public List<ApprovalModel> Approvers { get; set; }
[Required]
[Display(Name = "Please Select Your School")]
public string School { get; set; }
[Required]
[Display(Name = "Requestor")]
public string Requestor { get; set; }
[Display(Name = "Title")]
public string Title { get; set; }
[Required]
[DataType(DataType.PhoneNumber)]
[Display(Name = "Phone Number")]
[Phone]
public string PhoneNumber { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email Address")]
[EmailAddress]
public string Email { get; set; }
[Required]
[Display(Name = "Project Title")]
public string ProjectTitle { get; set; }
[Display(Name = "Requested Completion Date")]
public DateTime RequestedCompletionDate { get; set; }
[Required]
[Display(Name = "Project Description")]
public string ProjectDescription { get; set; }
[Display(Name = "Teacher/Room Number")]
public string TeacherGroup { get; set; }
[Display(Name = "1")]
public bool Grade1 { get; set; }
[Display(Name = "2")]
public bool Grade2 { get; set; }
[Display(Name = "3")]
public bool Grade3 { get; set; }
[Display(Name = "4")]
public bool Grade4 { get; set; }
[Display(Name = "5")]
public bool Grade5 { get; set; }
[Display(Name = "6")]
public bool Grade6 { get; set; }
[Display(Name = "7")]
public bool Grade7 { get; set; }
[Display(Name = "8")]
public bool Grade8 { get; set; }
[Display(Name = "9")]
public bool Grade9 { get; set; }
[Display(Name = "10")]
public bool Grade10 { get; set; }
[Display(Name = "11")]
public bool Grade11 { get; set; }
[Display(Name = "12")]
public bool Grade12 { get; set; }
[Display(Name = "Kindergarten")]
public bool Kindergarten { get; set; }
[Display(Name = "Describe how this plan will be continued if events cause programs or equipment to no longer be available. For example, if equipment purchased needs repair what funding source will be used for repair or replacement? For programs that have annual subscription fees, what funds will be used to continue the program from year to year?")]
public string Sustainability { get; set; }
public bool MultipleFundingSource { get; set; }
[Required(ErrorMessage="*")]
[Display(Name = "Funding Source")]
public string FundingSource1 { get; set; }
[Required(ErrorMessage = "*")]
public string FundingSource2 { get; set; }
[Required(ErrorMessage = "*")]
public string FundingSource3 { get; set; }
[Required(ErrorMessage = "*")]
public string FundingSource4 { get; set; }
[Required(ErrorMessage = "*")]
public string FundingSource5 { get; set; }
[Required]
[Display(Name = "Total Estimated Project Costs:")]
public float TotalEstimatedProjectCosts { get; set; }
//----------------------Additional Information
[Display(Name = "Additional Comments:")]
public string AdditionalComments { get; set; }
[Display(Name = "Additional Supporting Documents:")]
public string AdditionalSupportingDocuments { get; set; }
}
The exact error is:
An error occurred while executing the command definition. See the inner exception for details.
Inner Exception:
Invalid column name 'TechnologyProjectPlanModel_Id'.
That column name isn't referenced anywhere in my code, so it must be inferring it from something.
Any ideas? Thanks!
Entity Framework relies on conventions to determine what it thinks your DB looks like. In this case, it thinks the ApprovalModel table should have a foreign key to the TechnologyProjectPlanModel table. Trimming down your entities to the relevant fields, it becomes apparent why it thinks this:
public class ApprovalModel
{
}
public class TechnologyProjectPlanModel
{
public List<ApprovalModel> Approvers { get; set; }
}
In database terms, the relationship that would most likely exist in order for there to be multiple ApprovalModel's per TechnologyProjectPlanModel would be for ApprovalModel's to have a foreign key to TechnologyProjectPlanModel's.
How does TechnologyProjectPlanModel.Approvers get set? If it doesn't have anything to do with Entity Framework and you don't want it to try populating this property via it's conventions, you can explicitly tell it not to make that assumption by telling it the property is not mapped like so:
[NotMapped]
public List<ApprovalModel> Approvers { get; set; }
If you do have this relationship, you need to give EF some more context so it doesn't make best guess assumptions. For example, if the foreign key does exist, place it in ApprovalModel along with the relevant navigation property that can further tell EF what your DB looks like:
public class ApprovalModel
{
public int TechnologyProjectPlanModelId { get; set; }
// ForeignKey attribute usually not necessary unless you need to tell EF
// about a property that doesn't follow the usual "{OtherEntityName}Id"
// naming convention.
[ForeignKey("TechnologyProjectPlanModelId")]
public TechnologyProjectPlanModel TechnologyProjectPlanModel { get; set; }
}
public class TechnologyProjectPlanModel
{
public List<ApprovalModel> Approvers { get; set; }
}
You know if you do the mapping correctly, that block of code is unnecessary because EF will retrieve results.Approvers for you.
You can use the Attribute based mapping directly on your model or you can use the Code First Configuration to map your foreign key properly.
Once you've properly mapped the foreign key, the block of code you pasted is unnecessary, EF does the load for you.

How to use checklistbox to update roles in account in mvc3

I have any Model
public class Account
{
[Key]
public int AccountID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string FullName { get; set; }
}
And
public class Role
{
[Key]
public int RoleID { get; set; }
public string RoleKey { get; set; }
public string RoleName { get; set; }
}
And
public class AccountRole
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public string Role { get; set; }
}
I want to use one view update Account and list role to list checkbox. When I checked in checkbox then role to insert in to AccountRole.
Please tell me how to create my View.
Create a holder for a Role + a boolean IsSelected
public class SelectionRoles
{
public bool IsSelected { get; set;}
public Role OneRole { get; set; }
}
use this in your ViewModel as a List, pass it to your View and use it for display, when you submit your form you can check in your controller which roles are checked by looking in your ViewModel at the IsSelected boolean for each record in your SelectionRole List.

EF Code First and ASP.NET membership provider

I am building a web application using MVC 3. It has users with different roles and privileges. I am using EF Code First approach for database creation. My model class for user is:
public class Users
{
public int UserID { get; set; }
public Name Name { get; set; }
public Address Address { get; set; }
public Contact Contact { get; set; }
}
public class Name
{
[Required, MaxLength(50), Display(Name = "First Name"), Column("FirstName")]
public string FirstName { get; set; }
[MaxLength(50), Display(Name = "Middle Name"), Column("MiddleName")]
public string MiddleName { get; set; }
[Required, MaxLength(50), Display(Name = "Last Name"), Column("LastName")]
public string LastName { get; set; }
}
public class Address
{
[Required, MaxLength(50), Display(Name = "Street"), Column("Street")]
public string Street { get; set; }
[Required, MaxLength(50), Display(Name = "City"), Column("City")]
public string City { get; set; }
[Required, MaxLength(50), Display(Name = "Country"), Column("Country")]
public string Country { get; set; }
[Required, MaxLength(5), Display(Name = "Postal Code"), Column("PostalCode")]
public string PostalCode { get; set; }
}
public class Contact
{
[Required, MaxLength(50), Display(Name = "Email"), Column("Email")]
public string Email { get; set; }
[Required, MaxLength(50), Display(Name = "Phone"), Column("Phone")]
public string Phone { get; set; }
[Required, MaxLength(50), Display(Name = "Fax"), Column("Fax")]
public string Fax { get; set; }
}
But for roles and authentication I want to use the default aspnetdb.mdf of App_Data folder. How do I link my Users table with the default Users table of aspnetdb.mdf?
Since it seems like you are creating a new site and DB, I wouldn't go about it this way, unless you have to for whatever reason.
I would use UserProfile to store additional info like address, phone, fax, etc. for the user, take a look at the Membership User Profile API to add the custom properties.
Also this article may help, it's a bit old but it should help you if needed.

MVC 3 Dropdowns & Multiple Model ViewModel

I'm pretty new to MVC, but I'm trying to set up a two step user registration system. I have an register model and several other models in a viewmodel called Registration. A user will have a profile based on the register model and then they will select a Producer/Distributor/Restaurant/Importer that they are part of, or create a new one of those. My ViewModel that is returned doesn't validate or pickup the values in my dropdownlists. They populate correctly, but on the post they aren't in the vm. Below is my view/controller/and models. I've been searching the net for 2 days with no luck. Also, if you think my method of registration is wacky, let me know. Thanks!
controller:
public class RegistrationController : Controller
{
private vfContext db = new vfContext();
//
// GET: /Registration/
public ActionResult Register()
{
ViewBag.UserTypeID = new SelectList(db.UserTypes, "UserTypeID", "Name");
ViewBag.ProducerID = new SelectList(db.Producers, "ProducerID", "Name");
ViewBag.PublicationID = new SelectList(db.Publications, "PublicationID", "Name");
ViewBag.ImporterID = new SelectList(db.Importers, "ImporterID", "Name");
ViewBag.DistributorID = new SelectList(db.Distributors, "DistributorID", "Name");
ViewBag.RestaurantID = new SelectList(db.Restaurants, "RestaurantID", "Name");
RegistrationViewModel reg = new RegistrationViewModel();
ViewData.Model = reg;
return View("Registration");
}
[HttpPost]
public ActionResult Register(RegistrationViewModel vm)
{
if (ModelState.IsValid)
{
MembershipCreateStatus createStatus;
//email is userid
Membership.CreateUser(vm.Register.Email, vm.Register.Password, vm.Register.Email, null, null, true, null, out createStatus);
if (createStatus == MembershipCreateStatus.Success)
{
Profile current = Profile.GetProfile(vm.Register.Email);
current.FirstName = vm.Register.FirstName;
current.LastName = vm.Register.LastName;
current.Address1 = vm.Register.Address1;
current.Address2 = vm.Register.Address2;
current.City = vm.Register.City;
current.State = vm.Register.State;
current.Postal = vm.Register.Postal;
current.UserTypeID = vm.Register.UserTypeID;
view - i'm having a hard time copying it over, so the issue is with ddls, so here is how I have the user type id one done
#model vf2.Models.RegistrationViewModel
<div class="editor-label">
#Html.LabelFor(model => model.Register.UserTypeID, "User Type")
</div>
<div class="editor-field">
#Html.DropDownList("UserTypeID", String.Empty)
#Html.ValidationMessageFor(m => m.Register.UserTypeID)
</div>
Models:
public class RegistrationViewModel
{
public RegisterModel Register { get; set; }
public Producer Producer { get; set; }
public Distributor Distributor { get; set; }
//public Publication Publication { get; set; }
public Restaurant Restaurant { get; set; }
public Importer Importer { get; set; }
}
Here is my register model.
public class RegisterModel
{
//[Required]
//[Display(Name = "User name")]
//public string UserName { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Address")]
public string Address1 { get; set; }
[Display(Name = "Address Cont.")]
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Postal { get; set; }
public string Country { get; set; }
[DataType(DataType.PhoneNumber)]
public string Phone { get; set; }
public int ProducerID { get; set; }
public int DistributorID { get; set; }
public int PublicationID { get; set; }
public int ImporterID { get; set; }
public int RestaurantID { get; set; }
public virtual Producer Producer{ get; set; }
public virtual Distributor Distributor { get; set; }
public virtual Publication Publication { get; set; }
public virtual Importer Importer { get; set; }
public virtual Restaurant Restaurant { get; set; }
[Required]
public int UserTypeID { get; set; }
public virtual UserType UserType { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
producer model:
public class Producer
{
public int ProducerID { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Postal { get; set; }
public string Country { get; set; }
[DataType(DataType.PhoneNumber)]
public string Phone { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public string Website { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedOn { get; set; }
public string UpdatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
public Boolean Active { get; set; }
public virtual ICollection<Wine> Wines { get; set; }
}
I think I figured this out by adding a the following to my viewmodel:
public IEnumerable<UserType> UserTypes { get; set; }
public IEnumerable<Producer> Producers { get; set; }
and then this to my view:
#Html.DropDownListFor(m=>m.Register.UserTypeID,new SelectList(Model.UserTypes,"UserTypeID","Name"),"Select account type")

Resources