Saving multi-level entity - c#

I have a 3 level entity and I am having some trouble saving it.
public partial class Event
{
public Event()
{
Recurrences = new HashSet<Recurrence>();
}
public int Id { get; set; }
public string Title { get; set; }
public ICollection<Recurrence> Recurrences { get; set; }
}
public partial class Recurrence
{
public Recurrence()
{
AspNetUsers = new HashSet<AspNetUser>();
}
public int Id { get; set; }
public int EventId { get; set; }
public string Venue { get; set; }
public ICollection<AspNetUser> AspNetUsers { get; set; }
}
public partial class AspNetUser
{
public AspNetUser()
{
Recurrences = new HashSet<Recurrence>();
}
public string Id { get; set; }
public string UserName { get; set; }
public ICollection<Recurrence> Recurrences { get; set; }
}
The Post controller for the Event Class looks like this:
// POST: api/Events
[ResponseType(typeof(Event))]
public async Task<IHttpActionResult> PostEvent(EventDTO #event)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var newEvent = new Event();
newEvent.Title = #event.Title;
newEvent.EventTypeId = #event.EventTypeId;
var recurrence = new Recurrence();
recurrence.Venue = #event.Venue;
var users = db.AspNetUsers.Where(u => #event.UserId.Contains(u.Id));
foreach (var u in users)
recurrence.AspNetUsers.Add(u);
newEvent.Recurrences.Add(recurrence);
db.Events.Add(newEvent);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = newEvent.Id }, newEvent);
}
When I call the PostEvent method with an Event like DTO i get the http error code 500.
first, how can i add exception handling to capture the specific error and secondly, what I'm I doing wrong here?
Any help is deeply appreciated.
Thanks.

Related

ASP.Net Core 5.0 Binding model to action with [Bind] attribute for nested child collection

I am trying to bind a model in a post action method. i.e binding with the help of [Bind] attribute.
Where I post some fields for parent while a collection of child properties at the same time.
Supose I have parent as following
class Parent
{
int field0;
string field1;
string field2;
ICollection<Child> Children;
}
class Child
{
int field3;
string field4;
string field5;
}
at the time of binding I can choose fields to bind for simple binding like [Bind("field1, field2")] and to include children as well then [Bind("field1,field2,children")]
But I need to include some fields of children like children("field4", "field5")
Is there any possibility so that I can write like following
public IActionResult UTOneFlight([Bind("field1, field2, children(field4, field5)")] Parent p)
{
}
UPDATE
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UTOneFlight([Bind("FlightID, SrcAirportID, DestAirportID, FlightDate, Sector, RegistrationNo, FlightNo, CallSign, CrewMembers, EmbDetails, UpdateRemarks")] FlightViewModel f)
{
if (f != null && f.EmbDetails != null)
{
if (f.FlightID == 0)
{
var flight = new Flight()
{
EmbDetails = new List<EmbDetail>(),
FlightType = "emb",
AirlineOperatorID = _user.OperatorID,
SrcAirportID = f.SrcAirportID,
DestAirportID = f.DestAirportID,
FlightDate = f.FlightDate,
Sector = f.Sector.ToString().ToLower()[0],
FlightNo = f.FlightNo.Trim().ToLower(),
CallSign = f.CallSign.Trim().ToLower(),
RegistrationNo = f.RegistrationNo.Trim().ToLower(),
CrewMembers = f.CrewMembers,
UpdateRemarks = f.UpdateRemarks?? f.UpdateRemarks,
EmbDataStatus = 'u',
CreatedBy = _user.UserID
};
foreach (var e in f.EmbDetails)
{
flight.EmbDetails.Add(
new EmbDetail()
{
PaxType = e.PaxType,
PaxClass = e.PaxClass,
AdultPax = e.AdultPax,
Infants = e.Infants,
Dips = e.Dips,
FOC = e.FOC,
TransferPax = e.TransferPax,
CreatedBy = _user.UserID
}
);
}
await _db.AddAsync(flight);
return RedirectToAction("Index");
}
else
{
//var flight = await _db.SingleAsync<Flight>(x => x.FlightID == f.FlightID);
//return RedirectToAction("Index");
}
}
else
return NotFound();
}
and my models are
public class FlightViewModel
{
public long FlightID { get; set; }
public int SrcAirportID { get; set; }
public int DestAirportID { get; set; }
public string RegistrationNo { get; set; }
public string FlightNo { get; set; }
public string CallSign { get; set; }
public DateTime FlightDate { get; set; }
public int CrewMembers { get; set; }
public char Sector { get; set; }
public string UpdateRemarks { get; set; }
public ICollection<EmbDetViewModel> EmbDetails { get; set; }
}
and
public class EmbDetViewModel
{
public string PaxType { get; set; }
public char PaxClass { get; set; }
public int AdultPax { get; set; }
public int Infants { get; set; }
public int Dips { get; set; }
public int Crew { get; set; }
public int FOC { get; set; }
public int TransferPax { get; set; }
}
I need to write signature of the method like
public async Task<IActionResult> UTOneFlight([Bind("FlightID, SrcAirportID, DestAirportID, FlightDate, Sector, RegistrationNo, FlightNo, CallSign, CrewMembers, EmbDetails(PaxType, PaxClass), UpdateRemarks")] FlightViewModel f)
Please have a look at
EmbDetails(PaxType, PaxClass)
How do you send your request body? I test in my side and here's the result.
My model:
public class ParentTestModel
{
public int id { get; set; }
public ICollection<TestModel> testModels { get; set; }
}
public class TestModel
{
public string prefix { get; set; }
}
==============================Update=============================
I test in my side with [JsonIgnore] and the property which added this annotation will be ignored and this is suitable when the request body is a json object like the screenshot above. And if you are sending the request in form-data then you can use [Bind] annotation, I think you may have referred to this document.

Database values not changing

I have a post method in my controller that looks like this and I want AvailableSeats to reduce by 1 anytime I post the form. The problem is when I run the program for the very first time and post the form, everything works perfectly but for subsequent times, the database values for the AvailableSeats doesn't reduce by 1, it just remains constant and I can't figure out why.
[HttpPost]
public ActionResult Create(BookingViewModel viewModel)
{
if (viewModel.FromLocationId == viewModel.ToLocationId)
{
return RedirectToAction("Index");
}
var busFromDb = _context.Buses.First(c=>c.Id == viewModel.BusId);
var seatsFromDb = busFromDb.BusSeats;
var reduce = seatsFromDb - 1;
if (busFromDb != null)
{
var book = new Booking
{
AvailableSeats = reduce,
FromLocationId = viewModel.FromLocationId,
ToLocationId = viewModel.ToLocationId,
BusId = viewModel.BusId,
DateTime = viewModel.DateTime,
};
_context.Bookings.Add(book);
}
_context.SaveChanges();
return RedirectToAction("Index", "Home");
}
My Booking Class
public class Booking
{
[Required]
public int Id { get; set; }
public FromLocation FromLocation { get; set; }
public int FromLocationId { get; set; }
public ToLocation ToLocation { get; set; }
public int ToLocationId { get; set; }
public Bus Bus { get; set; }
[Required]
public int BusId { get; set; }
public DateTime DateTime { get; set; }
public int AvailableSeats { get; set; }
}
My Bus class
public class Bus
{
public int Id { get; set; }
public string BusNumber { get; set; }
public BusService BusService { get; set; }
public int BusSeats { get; set; }
}
As requested, this is my DbContext class
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Bus> Buses { get; set; }
public DbSet<Booking> Bookings { get; set; }
public DbSet<FromLocation> FromLocations { get; set; }
public DbSet<ToLocation> ToLocations { get; set; }
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
After which I initialized it in my controller.
public class BookingsController : Controller
{
private ApplicationDbContext _context;
public BookingsController()
{
_context = new ApplicationDbContext();
}
Currently, you are deducting total bus seats by 1 (24 - 1) that always return 23 for each booking because you don't update the value 24 from Bus table, I am assuming which is total number of seats in a given bus. Rather you can count total bookings made for per bus that gives you the remaining seats.
int seatsFromDb = busFromDb.BusSeats; //24
int soldSeats = _context.Bookings.Count(b => b.BusId == viewModel.BusId); //2 (you need to add more filters)
int remainingSeats = seatsFromDb - (soldSeats + 1) //include the current booking (sold 3)
var book = new Booking
{
AvailableSeats = remainingSeats,
// ...
Hi I tried this code with same entitty structure and now result is that on every booking the bus table BusSeats reduce to one and in Booking table availabe seats reduce to one. I think this is want you wanted.
public ActionResult Index()
{
-- I hardcoded id because I donthave all view model but with this i was able to achieve the result you required.
int BusId = 1;
var _context = new TestContext();
var busFromDb = _context.Buses.FirstOrDefault(c => c.Id == BusId);
var seatsFromDb = busFromDb.BusSeats;
var reduce = seatsFromDb - 1;
if (busFromDb != null)
{
busFromDb.BusSeats = busFromDb.BusSeats - 1;
var book = new Booking
{
AvailableSeats = reduce,
BusId = BusId,
DateTime =DateTime.Now,
Bus = busFromDb
};
book.Bus = busFromDb;
_context.Entry(busFromDb).State = EntityState.Modified;
_context.Bookings.Add(book);
}
_context.SaveChanges();
return View();
}
Below is my EF classes
public class TestContext:DbContext
{
public TestContext()
: base("name=TestConnection")
{
}
public virtual DbSet<Bus> Buses { get; set; }
public virtual DbSet<Booking> Bookings { get; set; }
}
}
public class Booking
{
public int Id { get; set; }
public Bus Bus { get; set; }
public int BusId { get; set; }
public DateTime DateTime { get; set; }
public int AvailableSeats { get; set; }
}
public class Bus
{
public int Id { get; set; }
public string BusNumber { get; set; }
public int BusSeats { get; set; }
}

How to get data out of sqlite database by using a function?

I am making a application in Xamarin forms but whatever I try I can't get the sqlite database working. I want to select all Categories where menu_ID = 1 how can I do this? I need this code inside a other page (CategoriePage.xaml.cs) can somewann help me with this?
Here is some code that I use:
(Tables.cs):
namespace AmsterdamTheMapV3
{
public class Categories
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public int Menu_ID { get; set; }
public string Name { get; set; }
public Categories()
{
}
}
public class Places
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public int Categorie_ID { get; set; }
public string Name { get; set; }
public Boolean Featured { get; set; }
public string OpenHours { get; set; }
public string Info { get; set; }
public string Images { get; set; }
public string Phone { get; set; }
public string Website { get; set; }
public string Adress { get; set; }
public Places()
{
}
}
public class Events
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public Events()
{
}
}
}
DB helper (TheMapDB.cs):
public class TheMapDB
{
private SQLiteConnection db;
public TheMapDB()
{
//Getting conection and Creating table
db = DependencyService.Get<ISQLite>().GetConnection();
db.CreateTable<Categories>();
db.CreateTable<Places>();
db.CreateTable<Events>();
var categories = new Categories()
{
ID = 1,
Menu_ID = 1,
Name = "test"
};
db.Insert(categories); // Insert the object in the database
}
public IEnumerable<Categories> GetCategories()
{
return (from t in db.Table<Categories>() select t).ToList();
}
//Get specific Categorie
public Categories GetCategorie(int id)
{
return db.Table<Categories>().FirstOrDefault(t => t.ID == id);
}
//Delete specific Categorie
public void DeleteCategorie(int id)
{
db.Delete<Categories>(id);
}
//Add new student to Categorie
public void AddCategorie(Categories categorie)
{
db.Insert(categorie);
}
}
}
CategoriePage.xaml.cs:
public partial class CategoriePage : ContentPage
{
static TheMapDB database;
TheMapDB categorie = new TheMapDB();
public CategoriePage(String txt)
{
InitializeComponent();
var layout = new StackLayout { Padding = new Thickness(5, 10) };
this.Content = layout;
if(txt.Equals("1"))
{
txt = "this text is number 1";
//needed code can't find soluction
}
var label = new Label { Text = txt, TextColor = Color.FromHex("#77d065"), FontSize = 20 };
layout.Children.Add(label);
}
}
thank you in advance,
I suggest you make a DAO class with a function like this: (or put this function in TheMapDB.cs)
public List<Category> GetCategoryByID(int menuID)
{
return db.Table<Category>().Where(x => x.menu_ID == menuID).ToList();
}
Then you can call this function in your DAO from everywhere you want. That seems the best solution to me.
When you put this function in the class TheMapDB.cs you can say in your CategoryPage.xaml.cs:
database.GetCategoryByID(menuID);

Entity framework with Web Api returning object

Hi I am new to entity framework. I have following objects
public partial class lr
{
public lr()
{
this.lr_history = new HashSet<lr_history>();
this.people = new HashSet<person>();
}
public int _id { get; set; }
public string name { get; set; }
public string notes { get; set; }
public virtual ICollection<lr_history> lr_history { get; set; }
public virtual ICollection<person> people { get; set; }
In my Web Api controller I have following code
public class lrController : ApiController
{
private CTM db = new CTM();
// GET api/addL
public IEnumerable<lr> Getlr()
{
from a in DbContext.Activities
return db.lr.AsEnumerable();
}
In above Get method it returns lr but i want to return my own object like
lr.id
lr.name
lr_history.description
lrh_history.rate
Can anyone show me how to achieve this? Than
Create a new model:
class HistoryModel
{
public int Id { get; set; }
public string Name { get; set; }
public string HistoryDescription { get; set; }
public string HistoryRate { get; set; }
}
and return that:
public IEnumerable<HistoryModel> Getlr()
{
from a in DbContext.Activities
return db.lr.AsEnumerable()
.Select(x => new HistoryModel
{
Id = x.id,
Name = x.name,
HistoryDescription = x.history.description,
HistoryRate = x.history.rate
});
}
Instade of return db.lr.AsEnumerable();
try this
return db.lr.ToList();

ViewModel adding custom class to another class

I created this viewmodel:
public class PlayerViewModel
{
PlayerRepository repo = new PlayerRepository();
public Player Player { get; set; }
public int SelectedUserID { get; set; }
public SelectList Users { get; set; }
public PlayerViewModel()
{
Player = new Player();
}
public PlayerViewModel(int id)
{
Player = repo.Retrieve(id);
Users = new SelectList(repo.GetUsers());
SelectedUserID = 0;
}
}
this I have in view:
#Html.DropDownListFor(x => x.SelectedUserID, Model.Users)
#Html.ValidationMessageFor(x => x.SelectedUserID)
and this in controller:
[Authorize]
public ActionResult Upravit(int id)
{
var playerview = new PlayerViewModel(id);
return View(playerview);
}
[Authorize,HttpPost]
public ActionResult Upravit(int id, PlayerViewModel playerView)
{
if (ModelState.IsValid)
{
playerView.Player.User = usRepo.GetUserById(playerView.SelectedUserID);
repo.Save(playerView.Player);
return RedirectToAction("Podrobnosti", new { id = playerView.Player.PlayerID });
}
return View(playerView);
}
Now I have problem that " The field SelectedUserID must be a number." and I have in dropdownlist UserName. I modified this many times, I tried with Dictionary and other ways but everyway has some problem. So I want just ask for best way to add custom class User to class Player.
Player class:
public class Player
{
// pokud použijeme virtual a vlastností tak nám EF rozšíří o další možnosti jako lazy loading a další
[Key]
public int PlayerID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Surname { get; set; }
public string PhotoUrl { get; set; }
public string Post { get; set; }
public virtual Team Team { get; set; }
public virtual User User { get; set; }
// public int UserID { get; set; }
//public virtual ICollection<Article> Articles { get; set; }
// Here could be next things as number, ...
}
Thanks
Use this constructor instead:
http://msdn.microsoft.com/en-us/library/dd505286.aspx
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
Something like this:
Users = new SelectList(repo.GetUsers(),"UserID", "UserName");

Categories

Resources