.NET web API one to many relation - asp.net

I'm building a one to many relation web API with .NET and got error 400.
I have two tables:
public class CarBrand
{
public int CarBrandId { get; set; }
public string Name { get; set; }
[JsonIgnore]
public List<CarModel> CarModels { get; set; } = new List<CarModel>();
}
public class CarModel
{
public int CarModelId { get; set; }
public string ModelName { get; set; }
public int CarBrandId { get; set; }
[JsonIgnore]
public CarBrand CarBrand { get; set; } = new CarBrand();
}
My Controller is:
[HttpPost]
public async Task<ActionResult<CarModel>> PostCarModel(CarModel carModel)
{
_context.CarModels.Add(carModel);
await _context.SaveChangesAsync();
return CreatedAtAction("GetCarModel", new { id = carModel.CarModelId }, carModel);
}
But when I make a POST request and try to add CarModel, I get error 400:
CarBrand:[
"This Field is required!"
]
Thanks!

Related

Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details

I'm Learning Webapi so I'm trying to build a simple Api connected to SQL server and I got this error when I add new Movie data
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Movies_SuperHeroes_HeroId". The conflict occurred in database "SupersDb", table "dbo.SuperHeroes", column 'HeroId'.
I have two models :
Superhero Model:
namespace SuperHeroesApi.Models
{
public class SuperHero
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int HeroId { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[MaxLength(100)]
public string FirstName { get; set; }
[MaxLength(100)]
public string LastName { get; set; }
[MaxLength(100)]
public string City { get; set; }
}
}
Movie Model :
namespace SuperHeroesApi.Models
{
public class Movie
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MovieId { get; set; }
[Required]
[MaxLength(100)]
public string Title { get; set; }
public int Year { get; set; }
public double Rate { get; set; }
public byte [] Poster { get; set; }
[ForeignKey("SuperHero")]
public int HeroId { get; set; }
//public string SuuperHeroName { get; set; }
public virtual SuperHero SuperHero { get; set; }
}
}
dto :
namespace SuperHeroesApi.Otds
{
public class MoviesDtos
{
public string Title { get; set; }
public int Year { get; set; }
public double Rate { get; set; }
public IFormFile Poster { get; set; }
[ForeignKey("SuperHero")]
public int HeroId { get; set; }
}
}
MoviesController:
using SuperHeroesApi.Otds;
namespace SuperHeroesApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
private readonly AppDbContext _dbContext;
private new List<string> _allowedExtention = new List<string> { "jbg", "png" };
private long _maxAllowedPosterSize = 5242880;
public MoviesController(AppDbContext dbContext)
{
_dbContext = dbContext;
}
[HttpGet]
public async Task<IActionResult>GetAllAsync()
{
var movie = await _dbContext.Movies.ToListAsync();
return Ok(movie);
}
[HttpPost]
public async Task <IActionResult> CreateAsync([FromForm] MoviesDtos dto)
{
if (_allowedExtention.Contains(Path.GetExtension(dto.Poster.FileName).ToLower()))
return BadRequest();
using var dataStream = new MemoryStream();
await dto.Poster.CopyToAsync(dataStream);
var movie = new Movie
{
Title = dto.Title,
Year = dto.Year,
Rate = dto.Rate,
Poster = dataStream.ToArray(),
};
await _dbContext.AddAsync(movie);
_dbContext.SaveChanges();
return Ok(movie);
}
}
}
You probably already have existing rows before you made changes to your schema. Now that you're creating a new foreignkey HeroId in movie which cannot be null and an integer for that matter which means it will be a zero by default. It becomes a problem for the existing rows because they will try to reference a Hero entity with Id of 0 which doesn't exist. So, the obvious solution is to make the foreign key nullable and redo the migrations
[ForeignKey("SuperHero")]
public int? HeroId { get; set; }

ServiceStack AutoQuery join use

After reading the documentation, I am not sure but I have come to the conclusion that when creating QueryDb, you cannot choose the columns to join by? And I am under the impression, you must have DTO object to copy to? You cannot copy to a regular object or a dynamic object?
public class SampleAutoQueryDb : QueryDb<MailResponseDetailOrm, object>, ILeftJoin<MailResponseDetailOrm, MailResponseOrm> { }
Can anyone provide any insight on joining my MailResponseOrm to MailResponseDetailOrm. MailResponseDetailOrm has 5 fields namely the Email address. And I would like MailResponseOrm to be joined to it by Email as well. I also, for good measure do not want to alter either columnname. Would I have to create a custom implementation or a service to do this?
UPDATE
Here is my code as posted below:
[Alias("MailReportsDetail")]
public class MailResponseDetailOrm
{
public string Email { get; set; }
public int ID { get; set; }
[Alias("RespDate")]
public DateTime? AddedDateTime { get; set; }
[Alias("DLReport")]
public string Action { get; set; }
public string ActionDetail { get; set; }
public string IP { get; set; }
public string UserAgent { get; set; }
public string EmailReferrer { get; set; }
}
[Alias("MailReports")]
public class MailResponseOrm
{
public int ID { get; set; }
public string Email { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string Company { get; set; }
public string Contact { get; set; }
public string Country { get; set; }
[Alias("LastMail")]
public DateTime? ModifiedDateTime { get; set; }
[Alias("LastReport")]
public string Action { get; set; }
public DateTime? OptOut { get; set; }
public string Part { get; set; }
public string Phone { get; set; }
public string PostalCode { get; set; }
public string Source { get; set; }
public string State { get; set; }
public string Title { get; set; }
#region Obsolete
[Obsolete]
public string Class { get; set; }
[Obsolete]
public string IP { get; set; }
#endregion
}
public class SampleAutoQueryDb : QueryDb<MailResponseDetailOrm> { }
public class MyQueryServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
// Override with custom implementation
public object Any(SampleAutoQueryDb query)
{
var q = AutoQuery.CreateQuery(query, base.Request);
q.Join<MailResponseDetailOrm, MailResponseOrm>((x, y) => x.Email == y.Email)
// .Select<MailResponseDetailOrm, MailResponseOrm>((x, y) => new { x.ID, y.Email })
;
return AutoQuery.Execute(query, q);
}
}
Joins in AutoQuery needs to use OrmLite's Joins Reference conventions and all AutoQuery Services results are returned in a Typed DTO, which by default is the table being queried or you can use the QueryDb<From,Into> base class to return a custom result of columns from multiple joined tables.
You would need to use a Custom AutoQuery Implementation or your own Service implementation if you need customizations beyond this, e.g:
public class SampleAutoQueryDb : QueryDb<MailResponseDetailOrm> { }
public class MyQueryServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
// Override with custom implementation
public object Any(SampleAutoQueryDb query)
{
var q = AutoQuery.CreateQuery(query, base.Request);
q.Join<MailResponseDetailOrm,MailResponseOrm>((x, y) => x.Email == y.Email);
return AutoQuery.Execute(query, q);
}
}
// The query to join 2 objects on field names not specifically set in the class.
var q = Db.From<MailResponseDetailOrm>().Join<MailResponseDetailOrm>(x,y) => x.Email = y.Email);
// Run the query
var results = Db.Select(q);

How to get dependent entities on ef core?

Here's my model schema.
This is the dependent entity
public class ArticleFee
{
public int ID { get; set; }
public string Description { get; set; }
public Type Type { get; set; }
public double? FixedFee { get; set; }
public int? RangeStart { get; set; }
public int? RangeEnd { get; set; }
public double? Percentage { get; set; }
[StringLengthAttribute(1, MinimumLength = 1)]
public string ArticleLetter { get; set; }
public Article Article { get; set; }
}
public class Article
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[KeyAttribute]
[StringLengthAttribute(1, MinimumLength = 1)]
public string Letter { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public ICollection<ArticleFee> ArticleFees { get; set; }
}
Here's how I show data on my route but the ArticleFees just shows an empty array.
[HttpGetAttribute]
public IEnumerable<Article> Get()
{
return _context.Articles
.Include(a => a.ArticleFees)
.ToList();
}
Your model is good(*) and the Get() method too. Your issue is that an infinite loop is detected during the JSON serialization because Article points to ArticleFee and ArticleFee points to Article.
To solve your problem, you must configure the app in Startup.cs so that it "ignore" instead of "throw exception" when such a loop is detected. The solution in .NET Core from this SO answer:
services.AddMvc().AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}); ;
You will need to add using Newtonsoft.Json; to the file.
(*) Assuming that your Type entity is fine.

Parse Complex JSON to ASP.NET MVC 3 using jQuery

I have to post this javascript object to asp.net controller:
The model in server side is:
public class UserExperience
{
public class competences
{
public string id { get; set; }
public string level { get; set; }
public string name { get; set; }
public bool isNew { get; set; }
public bool isSaved { get; set; }
}
public long id { get; set; }
public string startDate { get; set; }
public string endDate { get; set; }
public string projectName { get; set; }
public string company { get; set; }
public string customerIndustry { get; set; }
public string jobTitle { get; set; }
public string projectDescription { get; set; }
public string responsabilities { get; set; }
public List<competences> competence { get; set; }
public List<int> deletedCompetences { get; set; }
public bool isNew { get; set; }
public bool isSaved { get; set; }
}
I tried to send the json like this:
$.ajax("/candidate/saveUserExperience", {
data : JSON.stringify({ue: is.Candidate.BO.userExperience[id]}),
//dataType: "text",
contentType : "application/json",
type : 'POST'
})
And this is the controller where I receive it:
public JsonResult saveUserExperience(UserExperience ue)
{
bool success;
success = true;
return Json(new { success, ue }, JsonRequestBehavior.AllowGet);
}
And I receive a null object.
I tried to do with:
UserExperience userExperience = new JavaScriptSerializer().Deserialize<UserExperience>(ue);
and I do not receive the competence subclass object.
Is there a solution to this problem ?
Thanks.
Why are you trying to pass is.Candidate.BO.userExperience[id] when you expect UserExperience object? Just write data: ue in ajax call parameters,

ASP.NET MVC 4 Code First Many to Many Adding to Collection

I am using ASP.NET MVC 4 code first pattern for database layer. I have a many to many relationship between UserProfile and Task. When I try to add a task to the the collection of tasks of a user, it's added but if I try to query it and see if it's there it's not showing up.
My model:
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string SirName { get; set; }
public string Position { get; set; }
public string Email { get; set; }
public ICollection<TaskModels> Tasks {get; set; }
public bool? isActive { get; set; }
public UserProfile()
{
Tasks = new HashSet<TaskModels>();
}
}
public class TaskModels
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public ICollection<UserProfile> Employees { get; set; }
public int TimeNeeded { get; set; }
public int TimeWorked { get; set; }
public string Status { get; set; }
public bool isActive { get; set; }
public TaskModels()
{
Employees = new HashSet<UserProfile>();
}
}
public class WorkLogModels
{
public int Id { get; set; }
public UserProfile Author { get; set; }
public DateTime TimeBeganWorking { get; set; }
public int TimeWorkedOn { get; set; }
public TaskModels Task { get; set; }
public string Description { get; set; }
}
public class TimeTrackerDb : DbContext
{
public TimeTrackerDb() : base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<TaskModels> Tasks { get; set; }
public DbSet<WorkLogModels> WorkLogs { get; set; }
}
I try to check if a UserProfile already exists in a Task's Employees list and it's always empty.
[HttpPost]
public ActionResult Create(WorkLogModels worklogmodels)
{
var tasks = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).SingleOrDefault();
if (tasks == null)
{
return View(worklogmodels);
}
if (ModelState.IsValid)
{
var user = db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault();
var task = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault();
WorkLogModels log = new WorkLogModels();
log.Description = worklogmodels.Description;
log.TimeBeganWorking = worklogmodels.TimeBeganWorking;
log.TimeWorkedOn = worklogmodels.TimeWorkedOn;
log.Author = user;
log.Task = task;
db.WorkLogs.Add(log);
if (!db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).First().Tasks.Any(x=> x.Name == worklogmodels.Task.Name))
{
db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault().Tasks.Add(task);
db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault().Employees.Add(user);
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(worklogmodels);
}
I've been fighting with this for two days now.
Any help will be greatly appreciated
EDIT:
I am not sure if I made myself clear. In the Crate action for the WorkLog Controller I am trying to put the current user in the current task's collection and vice versa. It works correctly the first time, but then if I do it again it fails to skip the if statement and tries to add it once again and throws an exception : System.Data.SqlClient.SqlException. It's trying to add the same record to the intermediate table.

Resources