Entity Framework Code First relationship save Issue - asp.net

Having some troubles with saving new Employee to database.
Project Model(useless fiels removed):
public class Project{
public virtual ICollection<EmployeeManager.Employee> Employees { get; set; }
}
EmployeeManager.Employee Model:
public class Employee{
public virtual ApplicationUser User { get; set; }
public virtual ProjectsManager.Project ProjectObj { get; set; }
}
Function:
public async Task AddNewEmployeeAsync(string projectId, string email, string fullname){
var projectInfo = await GetByIdAsync(projectId);
var userInfo = new ApplicationUser();
if (await _context.Users.AnyAsync(_ => _.Email == email)){
userInfo = await _context.Users.FirstAsync(_ => _.Email == email);
}
else{
....
userInfo = user;
}
projectInfo.Employees.Add(new EmployeeManager.Employee{
User = userInfo
});
_context.Entry(projectInfo).State = EntityState.Modified;
_context.SaveChanges();
}
And after all that, i have no changes in database.
Why?
If i use _context.Employees.Add() -> it creates new project entity in database.

For Entity Framework to create the correct relationships (one to many) without configuration (FluentApi) you need to make a couple of changes to Employee class
public class Employee
{
public virtual ApplicationUser User { get; set; }
public int ProjectId { get; set; } //foreign key maybe a string as defined in your Project class
public virtual ProjectsManager.Project Project { get; set; }
}

Related

Handle POST requests with many-to-many relationships ASP.NET EFCore

I have these classes
public class Project
{
public Guid Id { get; set; }
public string DeployUrl { get; set; }
public List<Technology> Techs { get; set; } = new();
}
public class Technology
{
public Guid Id { get; set; }
public string Name { get; set; }
public string TechImg { get; set; }
[JsonIgnore]
public List<Project> Projects { get; set; } = new();
[JsonIgnore]
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
Which creates a many-to-many relationship. I want to add an endpoint to create a Project. The main issue here is the approach with which i'll do it. Since I don't send the full Technology object to the frontend, it would be impossible to send back a full Project as the request body for the endpoint since its Technology property would be missing fields, which posses an incompatibility with the actual entity in my server. Of course that the Technology instance already exists. So, what is the best approach here? Currently I'm sending a Project DTO that doesn't contain a List<Technology> but a List<Guid> of technologies, and in my repository I fetch from the DB all those technologies and add them manually. Is this correct? Thanks in advance.
public class ProjectPostDto
{
public string DeployUrl { get; set; }
public List<Guid> TechsIds { get; set; } = new();
}
public async Task<ActionResult> PostProject(ProjectPostDto projectDto)
{
try
{
Project newProject = FromPostDto(projectDto);
newProject.Techs = await Service.GetTechs(projectDto.TechsIds);
await Service.Create(newProject);
ProjectPostDto newProjectDto = ToPostDto(newProject);
return CreatedAtAction(nameof(GetProject), new { id = newProject.Id }, newProjectDto);
} catch (Exception)
{
return StatusCode(500, "Server error");
}
}

Create sub-type instances in ASP.NET Core 2.2

I am developing an ASP.NET Core application. There are several entities, some of which have one-to-many relations with each other i.e.
Project 1->* Priority, Project 1->* Milestone; Milestone 1->* Issue...
All navigation properties of all entities are virtual and I have already configured lazy loading in OnConfiguring method in the DbContext class:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
}
The situation is following: I have already created an instance or Project type and now I want to create instances of other sub-types which should be related to the already created Project instance.
My logic for creating of Priority instance is to pass a projectId to the priority entity which will be added to the corresponding DbSet.
The entity models:
public class Project
{
[Required]
public virtual ICollection<Priority> Priorities { get; set; }
}
public class Priority
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string ProjectId { get; set; }
[Required]
public virtual Project Project { get; set; }
}
The priorityInputModel from the form:
public class PriorityInputModel : IMapTo<PriorityServiceModel>
{
[Required]
public string Name { get; set; }
[Required]
public string ProjectId { get; set; }
}
The PriorityServiceModel:
public class PriorityServiceModel : IMapFrom<Priority>, IMapTo<Priority>
{
public int Id { get; set; }
public string Name { get; set; }
public string ProjectId { get; set; }
public ProjectServiceModel Project { get; set; }
}
The controller:
[HttpPost]
public async Task<ActionResult> Create(PriorityInputModel inputModel)
{
var priorityServiceModel = inputModel.To<PriorityServiceModel>();
var priorityServiceModelResult = await this.priorityService.CreateAsync(priorityServiceModel);
return this.RedirectToRoute(
routeName: ValuesConstants.DefaultRouteName,
routeValues: new
{
controller = ValuesConstants.ProjectControllerName,
action = ValuesConstants.DetailsActionName,
id = priorityServiceModelResult.ProjectId,
});
}
The service method:
public async Task<PriorityServiceModel> CreateAsync(PriorityServiceModel priorityServiceModel)
{
var priority = priorityServiceModel.To<Priority>();
var priorityResult = await this.repository.AddAsync(priority);
var priorityServiceModelResult = priorityResult.To<PriorityServiceModel>();
return priorityServiceModelResult;
}
The repository method:
public virtual async Task<TEntity> AddAsync(TEntity entity)
{
await this.DbSet.AddAsync(entity);
await this.SaveChangesAsync();
return entity;
}
I expected when the changes had been saved, the returned Priority object to have initialized Project navigation property with the corresponding project instance but the returned object has value as follows:
Priority {
"Id" = 33,
"Name" = "Lowest",
"ProjectId" = "bd15bd0c-fed7-4186-ade0-ad9338dff1d7"
"Project" = null
}
What is the reason for this and how could I receive the project instance initialized in the navigation property Project of newly created and returned Priority object?
Thanks in advance!

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.ConsoleUserInfoes_dbo.ConsolesCheckBoxes_consoleId"

I'm getting this error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.ConsoleUserInfoes_dbo.ConsolesCheckBoxes_consoleId". The conflict occurred in database "aspnet-ForePlay-20180525122039", table "dbo.ConsolesCheckBoxes", column 'ConsoleId'.
I'm using Entity Framework and ASP.NET MVC 5 and IdentityUser and try to insert data form checkListBox to table into my database.
This is happening on the register view, when user need to register and fill the form.
public class ConsoleUserInfo
{
[Key]
public int identity { get; set; }
[Required]
[StringLength(255)]
[ForeignKey("User")]
public string userid { get; set; }
[Required]
[ForeignKey("consolesCheckBox")]
public int consoleId { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual ConsolesCheckBox consolesCheckBox { get; set; }
}
This is the table that need to get a user id (form applictionUser) and consoleId
(form ConsolesCheckBox )
This is the ApplicationUserUser model class:
public class ApplicationUser : IdentityUser
{
[Required]
[StringLength(255)]
override
public string UserName { get; set; }
[Required]
[StringLength(50)]
public string Phone { get; set; }
public byte[] UserPhoto { get; set; }
public virtual UserAddress Address { get; set; }
public virtual ICollection<ConsolesCheckBox> consoleCheckBox { get; set; }
}
and this is the checkBoxList table:
public class ConsolesCheckBox
{
[Key]
public int ConsoleId { get; set; }
public string ConsoleName { get; set; }
public bool IsChecked { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
}
This is my account controller, all in the register get and post
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
//using database
using (ApplicationDbContext dbo = new ApplicationDbContext())
{
//data will save list of the consoleCheckBoxItem
var data = dbo.consolesCheckBox.ToList();
// because the view is request a common model, we will create new one
CommenModel a = new CommenModel();
a.ConsolesCheckBoxList = data;
// we will need to return common model, that way we will return a
return View(a);
}
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register([Bind(Exclude = "UserPhoto")]CommenModel model)
{
if (ModelState.IsValid)
{
// To convert the user uploaded Photo as Byte Array before save to DB
byte[] imageData = null;
if (Request.Files.Count > 0)
{
HttpPostedFileBase poImgFile = Request.Files["UserPhoto"];
using (var binary = new BinaryReader(poImgFile.InputStream))
{
imageData = binary.ReadBytes(poImgFile.ContentLength);
}
}
var user = new ApplicationUser
{
UserName = model.registerViewModel.Email,
Email = model.registerViewModel.Email,
Phone = model.registerViewModel.Phone
};
user.UserPhoto = imageData;
var result = await UserManager.CreateAsync(user, model.registerViewModel.Password);
//after the user create, we will use the id and add the id to the userAddress table include
// Address, longitude and latitude.
using (ApplicationDbContext dbo = new ApplicationDbContext())
{
var currentUserId = user.Id;
var pasinfo = dbo.userAddress.FirstOrDefault(d => d.Userid == currentUserId);
if (pasinfo == null)
{
pasinfo = dbo.userAddress.Create();
pasinfo.Userid = currentUserId;
dbo.userAddress.Add(pasinfo);
}
pasinfo.Address = model.useraddress.Address;
pasinfo.latitude = model.useraddress.latitude;
pasinfo.longitude = model.useraddress.longitude;
dbo.SaveChanges();
foreach (var item in model.ConsolesCheckBoxList.Where(x => x.IsChecked).Select(x => x.ConsoleId))
{
var consoleUserInfo = new ConsoleUserInfo
{
userid = currentUserId,
consoleId = item
};
dbo.consoleUserInfo.Add(consoleUserInfo);
}
dbo.SaveChanges();
}
}
}
In the register GET I have a common model, because I used 3 models in the view
this is the common model:
public class CommonModel
{
public UserAddress useraddress { get; set; }
public RegisterViewModel registerViewModel { get; set; }
public List<ConsolesCheckBox> ConsolesCheckBoxList { get; set; }
}
I need your help here, I've been trying to fix this all day.

How to join my tables with identity tables?

I started a default MVC project with Identity and EF.
In my app users will be able to create and edit some records.
In the table for these records, I want to have the ids of users who created the record and who updated lastly.
My model class is like:
public class Record
{
public int ID { get; set; }
public DateTime CreateTime { get; set; }
public string CreatingUserID { get; set; }
public string UpdatingUserID { get; set; }
public DateTime UpdateTime { get; set; }
public Enums.RecordStatus Status { get; set; }
}
And in RecordsController, I save new records to db like this:
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(FormCollection form, RecordCreateVM vm)
{
string userId = User.Identity.GetUserId();
DateTime now = DateTime.Now;
Record rec = new Record ();
if (ModelState.IsValid)
{
int newRecordId;
using (RecordRepository wr = new RecordRepository())
{
UpdateModel(rec);
rec.CreateTime = now;
rec.UpdateTime = now;
rec.CreatingUserID = userId;
rec.UpdatingUserID = userId;
rec.Status = Enums.RecordStatus.Active;
Record result = wr.Add(rec);
wr.SaveChanges();
newRecordId = result.ID;
}
}
}
When I am listing these records, I also want my page to display these users' usernames.
I get all the active records from the repository I created.
public ActionResult Index()
{
RecordListVMviewModel = new RecordListVM();
using (RecordRepository wr = new (RecordRepository())
{
viewModel.Records = wr.GetAll();
}
return View(viewModel);
}
And this is the repository code:
public class RecordRepository: Repository<Record>
{
public override List<Record> GetAll()
{
IQueryable<Record> activeRecords = DbSet.Where(w => w.Status == Enums.RecordStatus.Active);
return activeRecords.ToList();
}
}
Where do I have to make changes? Can you give me an sample code for usages like this?
Thank you.
You need to change
public string CreatingUserID { get; set; }
public string UpdatingUserID { get; set; }
to something like:
public User CreatingUser { get; set; }
public User UpdatingUser { get; set; }
Set the ID's during the creation of new RecordRepository()
Then access them as Record.CreatingUser.FirstName ect

Add list of models to Asp.net Identity

I want to assign a list of stores to a particular client, based on the Identity Model in MVC 5. I want to be able to register a user/client using the default registration in the MVC 5 example code and be able to add a store, then assign the store to the user.
I'm having trouble being able to create a working viewmodel that incorporates the idenity model with a new list.
Here is what I have so far:
Model:
public class ApplicationUser : IdentityUser
{
//[Required]
[Display(Name = "Client/Company Name")]
public string ClientName { get; set; }
public List<Store> Stores { 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;
}
}
I tried to add to the existing default dbcontext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Store> Stores { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
My controller blows up when I try to set my store clientname to the user clientname. Clientname or any other property is unavailable for ApplicationUser.
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Stores
public ActionResult Index(ClientStoreViewModel viewModel)
{
var clients = from s in db.Stores
join c in db.Users
on s.ClientName equals u.ClientName
select new ClientStoreViewModel() { Stores = s, Users = u };
return View(clients);
}
Store class:
public class Store
{
public int Id { get; set; }
//public int ClientId { get; set; }
[Display(Name = "Client Name")]
public string ClientName { get; set; }
[Display(Name = "Store Name")]
public string Brand { get; set; }
[Display(Name = "Store Number")]
public string StoreNumber { get; set; }
[Display(Name="Store Login URL")]
public string LoginURL { get; set; }
}
Finally my viewmodel:
public class ClientStoreViewModel
{
public ApplicationUser Users { get; set; }
public Store Stores { get; set; }
public ClientStoreViewModel()
{
Stores = new Store();
Users = new ApplicationUser();
}
}

Resources