I want to delete records from my database only which don't have any dependencies.
eg:- Company Table has Company Pk primary key and it is the foreign key for department table and location table. So the system should not allow user to delete a company from company if it has dependencies with department and location.
The records without any dependencies can be deleted. How can I do this?
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Payroll.Core.Domain;
using Payroll.Infrastructure.Data;
using AutoMapper;
using Payroll.Web.Dto;
using Payroll.Core.Interfaces;
using Payroll.Infrastructure.Validators;
namespace Payroll.Web.Controllers
{
[RoutePrefix("Company")]
public class CompanyController : Controller
{
private readonly IMapper _mapper = null;
private readonly IUnitOfWork _work = null;
public CompanyController(IUnitOfWork work, IMapper mapper)
{
_work = work;
_mapper = mapper;
}
// GET: Company
public async Task<ActionResult> Index()
{
var companies = await _work.Companies.GetAllAsync();
var companyDtos = _mapper.Map<List<CompanyDto>>(companies);
return View(companyDtos);
}
// GET: Company/5
[Route("{companyPk:int}")]
public async Task<ActionResult> Details(int? companyPk)
{
//Validate parameters
if (companyPk == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Company identifier is missing.");
}
//Get model from db
Company company = await _work.Companies.GetAsync(companyPk);
if (company == null)
{
return HttpNotFound();
}
//Convert model to dto
CompanyDto companyDto = _mapper.Map<CompanyDto>(company);
return View(companyDto);
}
// GET: Company/New
[Route("New")]
public ActionResult New()
{
var dto = new CompanyDto();
return View(dto);
}
// POST: Company/New
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[Route("New")]
public async Task<ActionResult> New(CompanyDto companyDto)
{
//Validate Dto state
if (ModelState.IsValid)
{
//Convert dto to model
Company company = _mapper.Map<Company>(companyDto);
//Assign model properties
company.CompanyPk = new Random().Next(1, 10);
Utilities.Instance.SetEntityProperties(company);
//Validate model
var validator = new CompanyValidator();
var validation = await validator.ValidateAsync(company);
if (validation.IsValid)
{
//Save model to db
_work.Companies.Add(company);
await _work.CompleteAsync();
return RedirectToAction("Index");
}
else
{
foreach (var error in validation.Errors)
{
ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
}
}
}
return View(companyDto);
}
// GET: Company/5/Edit
[Route("{companyPk:int}/Edit")]
public async Task<ActionResult> Edit(int? companyPk)
{
//Validate parameters
if (companyPk == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Company identifier is missing.");
}
//Get the model from db
Company company = await _work.Companies.GetAsync(companyPk);
if (company == null)
{
return HttpNotFound();
}
//Convert model to dto
CompanyDto companyDto = _mapper.Map<CompanyDto>(company);
return View(companyDto);
}
// POST: Company/5/Edit
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[Route("{companyPk:int}/Edit")]
public async Task<ActionResult> Edit(int? companyPk, CompanyDto companyDto)
{
//Validate parameters
if (companyPk == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Company identifier is missing.");
}
//Validate Dto state
if (ModelState.IsValid)
{
//Get the model from db
//Because the record now being edited can be changed by another process
var company = await _work.Companies.GetAsync(companyPk);
if (company == null)
{
return HttpNotFound();
}
//Map the previous state of the model to log
var logCompany = _mapper.Map<LogCompany>(company);
//Convert dto to model
//This is a specific mapping which modifies the original model from only bound properties of Dto
_mapper.Map(companyDto, company);
//Validate model
var validator = new CompanyValidator();
var validation = await validator.ValidateAsync(company);
if (validation.IsValid)
{
//Assign log model properties
logCompany.RecordId = 0;
Utilities.Instance.SetLogEntityProperties(logCompany, "E");
//Save model to db
_work.LogCompanies.Add(logCompany);
_work.Companies.Update(company);
await _work.CompleteAsync();
return RedirectToAction("Index");
}
else
{
foreach (var error in validation.Errors)
{
ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
}
}
}
return View(companyDto);
}
// GET: Company/5/Delete
[Route("{companyPk:int}/Delete")]
public async Task<ActionResult> Delete(int? companyPk)
{
//Validate parameters
if (companyPk == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Company identifier is missing.");
}
//Get the model from db
Company company = await _work.Companies.GetAsync(companyPk);
if (company == null)
{
return HttpNotFound();
}
//Convert model to dto
CompanyDto companyDto = _mapper.Map<CompanyDto>(company);
return View(companyDto);
}
// POST: Company/5/Delete
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
[Route("{companyPk:int}/Delete")]
public async Task<ActionResult> DeleteConfirmed(int companyPk)
{
//Get the model from db
Company company = await _work.Companies.GetAsync(companyPk);
//Prepare log model
var logCompany = _mapper.Map<LogCompany>(company);
logCompany.RecordId = 0;
Utilities.Instance.SetLogEntityProperties(logCompany, "D");
//Save model to db
_work.LogCompanies.Add(logCompany);
_work.Companies.Remove(company);
await _work.CompleteAsync();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_work.Dispose();
}
base.Dispose(disposing);
}
}
}
If you have navigation properties in your entity then you can just check if their keys are not null:
company.LocationId !=null && company.DepartmentId!=null
If you don't have Id properties (EF can create them conventionally) then read this documentation and load entities. Assuming that will not add much overhead.
var company = _work.Companies.Where(b => b.CompanyPk == companyPk)
.Include(b => b.Location)
.Include(b => b.Department)
.FirstOrDefault();
company.Location !=null && company.Department!=null
Hoping this is not a production code:
company.CompanyPk = new Random().Next(1, 10);
And never-ever destroy the injected dependency. This is a red flag as you don't control its lifetime, what if there is a pool? The rule is - you didn't create it, you are not responsible to destroy it. If you want explicitly control lifetime - then inject a Factory, create a service, use and destroy.
_work.Dispose();
Related
I'm customizing an old web application, built on ASP.NET MVC 5, .NET 4.6, Entity Framework 6.
I used Entity Framework to built it with a database-first approach. I have not used DDD / Repository / Services layer (it's a simple architecture).
I need to do this:
I don't want to massively update database records
Every time that I create/edit/list a PERSON_ENTITY item or dataset, I run a method on it
For example, turn to upper case FIRSTNAME and LASTNAME properties/fields or round DAYS_FROM_LAST_LOGIN
I don't want duplicate code in create/edit/list action of PERSON_ENTITY controller
namespace Webapplication4.Controllers
{
[Authorize]
public class PersonsController : Controller
{
private CS_Webapplication4_Entities db = new CS_Webapplication4_Entities();
public ActionResult Index()
{
var myDataset = db.PERSON_ENTITY ;
//----------------------------------** 1° point **
foreach(PERSON_ENTITY myPerson in myDataset)
{
myPerson.Firstname = Utils.Upperize(myPerson.Firstname);
myPerson.Lastname = Utils.Upperize(myPerson.Lastname);
}
return View(myDataset.ToList());
}
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
PERSON_ENTITY myPerson = db.PERSON_ENTITY.Find(id);
if (myPerson == null)
{
return HttpNotFound();
}
////---------------------------------- 2° point
myPerson.Firstname = Utils.Upperize(myPerson.Firstname);
myPerson.Lastname = Utils.Upperize(myPerson.Lastname);
return View(myPerson);
}
public ActionResult Create()
{
//...
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "...")] PERSON_ENTITY myPerson)
{
if (ModelState.IsValid)
{
//3° point
myPerson.Firstname = Utils.Upperize(myPerson.Firstname);
myPerson.Lastname = Utils.Upperize(myPerson.Lastname);
db.PERSON_ENTITY.Add(myPerson);
db.SaveChanges();
return RedirectToAction("Index");
}
//...
return View(myPerson);
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
PERSON_ENTITY myPerson = db.PERSON_ENTITY.Find(id);
if (myPerson == null)
{
return HttpNotFound();
}
//...
//4° point
myPerson.Firstname = Utils.Upperize(myPerson.Firstname);
myPerson.Lastname = Utils.Upperize(myPerson.Lastname);
return View(myPerson);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "...")] PERSON_ENTITY myPerson)
{
//5° point
myPerson.Firstname = Utils.Upperize(myPerson.Firstname);
myPerson.Lastname = Utils.Upperize(myPerson.Lastname);
if (ModelState.IsValid)
{
db.Entry(myPerson).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
//...
return View(myPerson);
}
}
}
I read that is possible to extend Entity Framework, by adding some extension methods. If that's possible, I can write something like this:
public static AppIdentityDbContext MyExtension()
{
var MyCustomizedMethod = new SOMETHING() {
if EntityType.Equals(PERSON_ENTITY)
{
PERSON_ENTITY.Firstname = Utils.Upperize(myPerson.Firstname);
PERSON_ENTITY.Lastname = Utils.Upperize(myPerson.Lastname);
}
};
return new AppIdentityDbContext().AddSomething(MyCustomizedMethod);;
}
Please, can someone help me to do this?
Is it possible to extend Entity Framework as outlined above?
Thanks to all
Well, you've almost done it. First deifine a static class for the context's extensions and add your new custom extension method
public static class AppIdentityDbContextExtensions()
{
public static bool AddSomething(this AppIdentityDbContext appIdentityDbContext )
{
<your-code-here>
};
}
And then call the new extension method like this
return new AppIdentityDbContex().AddSomething();
I have created the following web service and can access it by:
https://localhost:44311/valores/1
but I want to access it with a url like:
https://localhost:44311/usuario/1
using usuario in the url
[HttpGet("{id:int}",Name ="usuario")]
public ActionResult<Usuario> Get(int id)
{
using (var db = new prueba2Context())
{
var usuario = db.Usuario.Where(x => x.Id == id).FirstOrDefault();
if (usuario == null)
{
return NotFound();
}
return Ok(usuario);
}
}
I am new to c#, I appreciate if you indicate what I am doing wrong and how to correct it.
This is the structure of my folder.
It looks like you are using ASP.NET Core. A typical endpoint will be set up like this:
[ApiController, Route("api/[controller]")]
public class ComputationController : ControllerBase
{
// ...
[HttpPost, Route("beginComputation")]
[ProducesResponseType(StatusCodes.Status202Accepted, Type = typeof(JobCreatedModel))]
public async Task<IActionResult> BeginComputation([FromBody] JobParametersModel obj)
{
return Accepted(
await _queuedBackgroundService.PostWorkItemAsync(obj).ConfigureAwait(false));
}
[HttpGet, Route("computationStatus/{jobId}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(JobModel))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(string))]
public async Task<IActionResult> GetComputationResultAsync(string jobId)
{
var job = await _computationJobStatusService.GetJobAsync(jobId).ConfigureAwait(false);
if(job != null)
{
return Ok(job);
}
return NotFound($"Job with ID `{jobId}` not found");
}
// ...
}
The [ProducesResponseType] attribute is for documentation frameworks such as Swagger.
I always use the [Route] attribute to define the endpoint path.
In your case, I would set it up as so:
[HttpGet, Route("usuario/{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Usuario))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetUser(int id)
{
using (var db = new prueba2Context())
{
var usuario = await db.Usuario.Where(x => x.Id == id).FirstOrDefault();
if (usuario == null)
{
return NotFound();
}
return Ok(usuario);
}
}
Is more common use "Route"
like that
`[Route("usuario")]
public ActionResult<Usuario> Get(int id)
{
using (var db = new prueba2Context())
{
var usuario = db.Usuario.Where(x => x.Id == id).FirstOrDefault();
if (usuario == null)
{
return NotFound();
}
return Ok(usuario);
}
}
`
Ok I am using a session variable to store a case Id that is linked between tables. I am using .net 3.1 I just need this simple value passed between controllers It appears to only work within the current controller.
Say Relationship Controller is this.
public class RelationShipsController : Controller
{
private readonly MISDBContext _context;
public RelationShipsController(MISDBContext context)
{
_context = context;
}
// GET: RelationShips/Edit/5
public async Task<IActionResult> Edit(int? id) {
if (id == null) {
return NotFound();
}
var relationShips = await _context.RelationShips.FindAsync(id);
if (relationShips == null) {
return NotFound();
}
HttpContext.Session.SetString("relationShipId", relationShips.Id.ToString());
HttpContext.Session.SetString("CaseId", relationShips.MisObjectId.ToString());
return View(relationShips);
}
}
This is the second controller where i wish to read in the above session.
public class VesselsController : Controller
{
private readonly MISDBContext _context;
public VesselsController(MISDBContext context) {
_context = context;
GetCompanies();
}
// POST: Vessels/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,CountryOfOrigon,CompanyId,IMONumber,Flag,Company,Country,CallSign,MMSI,VesselType,Active,isDeleted,isActive,CreatedDate,CreatedBy,MISObjectId,RelationShipId")] Vessels vessels)
{
if (ModelState.IsValid) {
var realtionShipId = Int32.TryParse(HttpContext.Session.GetString("relationShipId"), out int resultRelationshipId);
Int32.TryParse(HttpContext.Session.GetString("CaseId"), out Int32 resultCaseId);
vessels.isActive = true;
vessels.isDeleted = false;
vessels.CreatedBy = HttpContext.Session.GetString("Intitals");
vessels.LastModfiedDate = DateTime.Now;
vessels.CreatedDate = DateTime.Now;
vessels.LastModfiedBy = HttpContext.Session.GetString("Intitals");
vessels.MISObjectId = resultCaseId;
vessels.RelationShipId = resultRelationshipId;
_context.Add(vessels);
await _context.SaveChangesAsync();
return RedirectToAction("Edit", "Relationships", new { Id = vessels.MISObjectId });
}
GetCompanies();
return View(vessels);
}
}
Its this resultCaseId I have lost the variable and yes I have setup the configure middle ware.
app.UseSession();
Make sure you as the user have provided consent. Or mark the session cookie as "essential" like this:
services.AddSession(opts =>
{
opts.Cookie.IsEssential = true; // make the session cookie Essential
});
You can read more about GDPR changes in asp.net core here.
How can I get record by Id? I have the following code to create master detail pages in asp.net core controller, I am able to get all products using the following code and works perfect
Interface
public interface IProductService { Task<IList<ProductDTO>> GetProduct(); }
Controller Actions
public IActionResult Index()
{
return View();
}
[HttpGet]
public async Task<IActionResult> GetProducts()
{
var products = await ProductsService.GetProducts();
return Json(products);
}
But how can I get single record by Id to create a detail page.I tried this but doesn’t work
public IActionResult Detail()
{
return View();
}
[HttpGet]
public async Task<IActionResult> GetProductsDetail(int id)
{
var products = await ProductsService.GetProducts.find(id);
return Json(products);
}
GetProductCode
public class GetProducts_Action : BaseEFAction<GetProducts_Action_Request, GetProducts_Action_Response>
{
public IFileProvider FileProvider { get; }
public GetProducts_Action(ILogger<GetProducts_Action> logger, DBContext context, ITransactionManager scope, IFileProvider fileProvider) : base(logger, context, scope)
{
FileProvider = fileProvider;
}
protected override Task<GetProducts_Action_Response> PerformActionAsync(GetProducts_Action_Request request)
{
IList<ProductDTO> product;
using (var file = System.IO.File.OpenText(FileProvider.GetFileInfo("Product.json").PhysicalPath))
{
var serializer = new JsonSerializer();
product = (IList<ProductDTO>)serializer.Deserialize(file, typeof(IList<ProductDTO>));
}
return Task.FromResult(new GetProducts_Action_Response { Products = product });
}
}
public class GetProducts_Action_Request : BaseActionRequest
{
}
public class GetProducts_Action_Response : BaseActionResponse
{
public IList<ProductDTO> Products { get; set; }
}
}
Given that your data source is actually a file and not a database, you're going to be deserializing that file each time anyway. That is your performance bottleneck. So if you want you can just use your existing GetProducts() service method and then filter in the controller (using LINQ). It's not a super clean way (code-wise), but the performance will basically be the same.
[HttpGet]
public async Task<IActionResult> GetProductsDetail(int id)
{
// Get all the products and then filter by id
// change "a.Id" to the actual DTO Id property name if different
var product = (await ProductsService.GetProducts()).FirstOrDefault(a => a.Id == id);
if (product != null) {
// If we found something, return that single ProductDTO
return Json(product);
} else {
// Not Found or whatever you want
return NotFound();
}
}
FirstOrDefault() will return the first object with your desired ID (assuming the ProductDTO property is called Id). If it doesn't find anything, it will return null, so then you probably want to return a 404 Not Found or something similar.
I understand that this general question has been asked and answered on here many times. Initially, this problem occurred for all of my web pages. I probably tried 15 different suggested fixes on here. Eventually using a response to a similar question, I ticked the 'Override application root URL' and now my homepage and the about page load correctly. However, the problem persists for my 'Movies' and 'Ratings' pages which are almost the same, which means it's most likely the code. I am obviously missing something and I'm very new to using c#, so I would greatly any help!
This is the error:
Server Error in '/' Application. The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /Movies
Here is my Movies controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using AllMovies.DAL;
using AllMovies.Models;
namespace AllMovies.Controllers
{
public class MoviesController : ApiController
{
private AllMoviesContext db = new AllMoviesContext();
// GET: api/Movies
public IQueryable<MovieDTO> GetMovies()
{
var movies = from m in db.Movies
select new MovieDTO()
{
Id = m.Id,
Name = m.Name,
Genre = m.Genre,
Budget = m.Budget,
Overview = m.Overview,
release_date = m.release_date,
Ratings = m.Ratings.Select(r => new RatingDTO()
{
Id = r.Id,
userId = r.userId,
rating_score = r.rating_score
}
).ToList()
};
return movies;
}
// GET: api/Movies/5
[ResponseType(typeof(MovieDTO))]
public async Task<IHttpActionResult> GetMovies(int id)
{
Movie m = await db.Movies.FindAsync(id);
if (m == null)
{
return NotFound();
}
MovieDTO movie = new MovieDTO
{
Id = m.Id,
Name = m.Name,
Genre = m.Genre,
Budget = m.Budget,
Overview = m.Overview,
release_date = m.release_date,
Ratings = m.Ratings.Select(r => new RatingDTO()
{
Id = r.Id,
userId = r.userId,
rating_score = r.rating_score
}
).ToList()
};
return Ok(movie);
}
// PUT: api/Movies/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutMovies(int id, Movie movie)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != movie.Id)
{
return BadRequest();
}
db.Entry(movie).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Movies
[ResponseType(typeof(Movie))]
public async Task<IHttpActionResult> PostMovies(Movie movie)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Movies.Add(movie);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = movie.Id }, movie);
}
// DELETE: api/Movies/5
[ResponseType(typeof(Movie))]
public async Task<IHttpActionResult> DeleteMovie(int id)
{
Movie movie = await db.Movies.FindAsync(id);
if (movie == null)
{
return NotFound();
}
db.Movies.Remove(movie);
await db.SaveChangesAsync();
return Ok(movie);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool MovieExists(int id)
{
return db.Movies.Count(e => e.Id == id) > 0;
}
}
}