Model property concatenated from properties in different models - c#

I created entity in database using code first, which mostly refers to the dictionary tables:
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Material Material { get; set; }
public int MaterialId { get; set; }
public Supplier Supplier { get; set; }
public int SupplierId { get; set; }
public Charact Charact { get; set; }
public int CharactId { get; set; }
public ItemType ItemType { get; set; }
public int ItemTypeId { get; set; }
public Size Size { get; set; }
public int SizeId { get; set; }
public int GroupId { get; set; }
public Group Group { get; set; }
public string Number { get; set; }
public string DescriptionSum { get; set; }
}
All dictionary models have similar properties, where property 'No' is key property in this case and is one or two character string:
public class Size
{
public int Id { get; set; }
public string Name { get; set; }
public string No { get; set; }
}
While creating new Item, user will select one record from each all avaliable in dictionary tables and save them in the Item table:
ItemsController for Create:
// GET: Items/Create
public IActionResult Create(int? gr)
{
ViewData["CharactId"] = new SelectList(_context.Charact, "Id", "Name");
ViewData["GroupId"] = new SelectList(_context.Group, "Id", "Name");
ViewData["ItemTypeId"] = new SelectList(_context.ItemType.Where(ItemType => ItemType.GroupId == gr), "Id", "Name");
ViewData["MaterialId"] = new SelectList(_context.Materials, "Id", "Name");
ViewData["SizeId"] = new SelectList(_context.Size, "Id", "Name");
ViewData["SupplierId"] = new SelectList(_context.Supplier.Where(Supplier => Supplier.GroupId == gr), "Id", "Name");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,Description,MaterialId,SupplierId,CharactId,ItemTypeId,SizeId,GroupId,Number,DescriptionSum")] Item item)
{
if (ModelState.IsValid)
{
_context.Add(item);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["CharactId"] = new SelectList(_context.Charact, "Id", "Name", item.CharactId);
ViewData["GroupId"] = new SelectList(_context.Group, "Id", "Name", item.GroupId);
ViewData["ItemTypeId"] = new SelectList(_context.ItemType, "Id", "Name", item.ItemTypeId);
ViewData["MaterialId"] = new SelectList(_context.Materials, "Id", "Name", item.MaterialId);
ViewData["SizeId"] = new SelectList(_context.Size, "Id", "Name", item.SizeId);
ViewData["SupplierId"] = new SelectList(_context.Supplier, "Id", "Name", item.SupplierId);
return View(item);
}
What I am trying to do is to "automatically" populate Number property, accordingly to selected in form options, based on 'No' properties and save it in database:
Number = Group.No + Supplier.No + ItemType.No + Charact.No + Material.No + Size.No;
Concatenated number would define chosen configuration of options. Because the same "No" can occure multiple times in the same table, it cannot be used as identification column.
I have tried few approaches, which I found in web:
Updating ItemController:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult>Create([Bind("Id,Name,Description,MaterialId,SupplierId,CharactId,ItemTypeId,SizeId,GroupId,Number,DescriptionSum")] Item item)
{
if (ModelState.IsValid)
{
item.Number = item.Group.No + item.Supplier.No + item.ItemType.No + item.Charact.No + item.Material.No + item.Size.No;
_context.Add(item);
await _context.SaveChangesAsync();
}
ViewData["CharactId"] = new SelectList(_context.Charact, "Id", "Name", item.CharactId);
ViewData["GroupId"] = new SelectList(_context.Group, "Id", "Name", item.GroupId);
ViewData["ItemTypeId"] = new SelectList(_context.ItemType, "Id", "Name", item.ItemTypeId);
ViewData["MaterialId"] = new SelectList(_context.Materials, "Id", "Name", item.MaterialId);
ViewData["SizeId"] = new SelectList(_context.Size, "Id", "Name", item.SizeId);
ViewData["SupplierId"] = new SelectList(_context.Supplier, "Id", "Name", item.SupplierId);
return View(item);
}
Exception occurred:
An unhandled exception occurred while processing the request.
NullReferenceException: Object reference not set to an instance of an object.
Database.Controllers.ItemsController.Create(Item item) in ItemsController.cs
item.Number = item.Group.No + item.Supplier.No + item.ItemType.No + item.Charact.No + item.Material.No + item.Size.No;
Changed model:
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Material Material { get; set; }
public int MaterialId { get; set; }
public Supplier Supplier { get; set; }
public int SupplierId { get; set; }
public Charact Charact { get; set; }
public int CharactId { get; set; }
public ItemType ItemType { get; set; }
public int ItemTypeId { get; set; }
public Size Size { get; set; }
public int SizeId { get; set; }
public int GroupId { get; set; }
public Group Group { get; set; }
public string Number
{ get
{
return this.Number = this.Group.No + this.Supplier.No + this.ItemType.No + this.Charact.No + this.Material.No + this.Size.No;
}
private set { }
}
public string DescriptionSum { get; set; }
}
Same Exception but concerning line
public string Number { get { return this.Number = this.Group.No + this.Supplier.No + this.ItemType.No + this.Charact.No + this.Material.No + this.Size.No; } private set { } }
in Item model.
Other model change:
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Material Material { get; set; }
public int MaterialId { get; set; }
public Supplier Supplier { get; set; }
public int SupplierId { get; set; }
public Charact Charact { get; set; }
public int CharactId { get; set; }
public ItemType ItemType { get; set; }
public int ItemTypeId { get; set; }
public Size Size { get; set; }
public int SizeId { get; set; }
public int GroupId { get; set; }
public Group Group { get; set; }
private string _value;
public string Number { get { return _value; } private set {_value = this.Group.No + this.Supplier.No + this.ItemType.No + this.Charact.No + this.Material.No + this.Size.No; } }
public string DescriptionSum { get; set; }
}
still same exception in line:
public string Number { get { return _value; } private set {_value = this.Group.No + this.Supplier.No + this.ItemType.No + this.Charact.No + this.Material.No + this.Size.No; } }
I couldn't find any other solutions. Please help.
BR

When you create instance of Item class; The material class & The Charact is class null. So when you try to access the Number it will throw object reference as Navigation Properties are null.
Option 1 Check Null and Assign the variable.
public string Number
{
get { return _value; }
private set {_value = this.Group?.No + this.Supplier?.No + this.ItemType?.No +
this.Charact?.No + this.Material?.No + this.Size?.No; }
}
If your using C# 6 or greater you can use this Null-Conditional Operators
Option 2 Fill the Navigation object with data.
public class Item
{
//YourProperties Here
public Item()
{
this.Material = new Material();
this.Charact = new Charact();
}
}
Basically you need to data to assign data to navigation property then it would work with your same code.

Related

Mvc Drop Down List With Repository

I am trying to get the id selected from a dropdown so that i can set it against my business logic method. I am using a repository pattern and my code is as follows.
However when i run the program, I get an error The insert statement conflicted with the foreign key.
Database Table
public class Item
{
[Key]
public int ItemId { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public string ItemArtUrl { get; set; }
public int CategoryId { get; set; }
[ForeignKey("CategoryId")]
public virtual Category Categories { get; set; }
}
Database table
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual IEnumerable<Item> Items { get; set; }
}
ViewModel
public class ItemViewModel
{
[Key]
public int ItemId { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public string ItemArtUrl { get; set; }
public int CategoryId { get; set; }
[ForeignKey("CategoryId")]
public IEnumerable<SelectListItem> CategoriesSelectListItem { get; set;}
}
ViewModel
public class CategoryViewModel
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
Business Logic Layer
public class ItemBusiness : IItemBusiness
{
public void Insert(ItemViewModel item)
{
var itemrepo = new ItemRepository();
Item i = new Item();
i.Title = item.Title;
i.Price = item.Price;
i.ItemArtUrl = item.ItemArtUrl;
i.CategoryId = item.CategoryId;
itemrepo.Insert(i);
}
public List<ItemViewModel> GetAllItems()
{
var itemrepo = new ItemRepository();
var query = (from x in itemrepo.GetAll()
select new ItemViewModel()
{
Title = x.Title,
Price = x.Price,
ItemArtUrl = x.ItemArtUrl,
CategoryId = x.CategoryId
}).ToList();
return query;
}
}
Controller
[HttpGet]
public ActionResult Create()
{
var categoryBusiness = new CategoryBusiness();
ViewBag.items = new SelectList(categoryBusiness.GetAllCategories(), "CategoryId", "Name");
return View();
}
[HttpPost]
public ActionResult Create(ItemViewModel item)
{
var itemBusiness = new ItemBusiness();
itemBusiness.Insert(item);
return View();
}
public ActionResult Index()
{
var itemBusiness = new ItemBusiness();
return View(itemBusiness.GetAllItems());
}
}
I am assuming your Create view is set up to use ItemViewModel since you are returning it in the [HTTPPost] So instead of using ViewBag.Items = dropdownlist, set your ItemViewModel.CategoriesSelectListItem to that list.
You would have to change your Controller to send an 'empty' ItemViewModel except with the CategoriesSelectionListItem
public ActionResult Create()
{
ItemViewModel ivm = new ItemViewModel();
var categoryBusiness = new CategoryBusiness();
ivm.CategoriesSelectionListItem = new SelectList(categoryBusiness.GetAllCategories(), "CategoryId", "Name");
return View(ivm);
}
Then in your view set up the dropdownlist like this and it will return the CategoryId as part of the Model
#Html.DropDownList("CategoryId", Model.CategoriesSelectListItem, htmlAttributes: new { #class = "form-control" })

Need to compare value from other table

I have 3 classes in my model
Model
public class Student
{
public int id { get; set; }
[Required]
[DisplayName("Student Name")]
public string Name { get; set; }
[Required]
public int RollNO { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Record> Records { get; set; }
}
public class Record
{
public int Id { get; set; }
public int StudentId { get; set; }
public int SubjectId { get; set; }
[Required]
public int Marks { get; set; }
public string Result { get; set; }
public virtual Student Students { get; set; }
public virtual Subject Subjects { get; set; }
}
public class Subject
{
public int id { get; set; }
[Required]
public string Title { get; set; }
[Required]
[DisplayName("Minimum Marks")]
public int MinMarks { get; set; }
[Required]
[DisplayName("Max Marks")]
public int MaxMarks { get; set; }
public ICollection<Record> Records { get; set; }
}
In subject table i will be creating each subject and setting its minimum and maximum marks required to pass...now in record table (Create Page) i want to compare the selected subject minimum marks with Record.Marks and if its less the minimum marks get Fail in Record.Result and if its greater then maximum marks get Pass in Record.Result...and i also want to compare the Result.Marks property with Subject.MaxMarks and if its greater then Subject.MaxMarks the user should get error in any form possible...
this is my controller
Controller
public ActionResult Create([Bind(Include = "Id,StudentId,SubjectId,Marks,Result")] Record record,Subject subject)
{
var selectedSubject = db.Subjects.Where(sub => subject.id == record.SubjectId).FirstOrDefault();
if (record.Marks < selectedSubject.MinMarks)
{
record.Result = "Fail";
}
else
record.Result = "Pass";
if (ModelState.IsValid)
{
db.Records.Add(record);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.StudentId = new SelectList(db.Students, "id", "Name", record.StudentId);
ViewBag.SubjectId = new SelectList(db.Subjects, "id", "Title", record.SubjectId);
return View(record);
}
Assuming your view has the input element to select/enter the subject id and the element's name attribute value is SubjectId and it is inside the form
Just add an else if to check max mark as well. You do not need the second parameter in your action method. Just remove it.
var selectedSubject = db.Subjects.FirstOrDefault(a=> a.id == record.SubjectId);
if(selectedSubject!=null)
{
if (record.Marks < selectedSubject.MinMarks)
{
record.Result = "Fail";
}
else if (record.Marks > selectedSubject.MaxMarks)
{
record.Result = "Error";
}
else
{
record.Result = "Pass";
}
}
else
{
ModelState.AddModeError(string.empty,"Subject not found");
}
//to do : Reload dropdown data and return the view

WPF, C# - group by object property

Is there a posibility to group by an object property in wpf?
For exmaple:
public class Ausgabe
{
public int Id { get; set; }
public Mitarbeiter Mitarbeiter { get; set; }
public Ausgabestatus Status { get; set; }
public Bestellung Bestellung { get; set; }
}
public class Mitarbeiter
{
public int Id { get; set; }
public String Vorname { get; set; }
public String Nachname { get; set; }
public String FullName
{
get { return Nachname + " " + Vorname; }
}
}
My datagrid's ItemsSource contains a List<Ausgabe> which i want to group by Mitarbeiter.FullName
CollectionView cv = (CollectionView)CollectionViewSource.GetDefaultView(dgErfasst.ItemsSource);
cv.GroupDescriptions.Clear();
PropertyGroupDescription pgd = new PropertyGroupDescription("Mitarbeiter.Vorname");
cv.GroupDescriptions.Add(pgd);
This does not seem to work. Is there a way to achieve this kind of grouping?
You can move FullName to parent class like
public class Ausgabe
{
public int Id { get; set; }
public Mitarbeiter Mitarbeiter { get; set; }
public Ausgabestatus Status { get; set; }
public Bestellung Bestellung { get; set; }
public String FullName
{
get { return Mitarbeiter.Nachname + " " + Mitarbeiter.Vorname; }
}
}
and then group
PropertyGroupDescription pgd = new PropertyGroupDescription("FullName");

ViewModel save selected value from dropdownlist

I have a dropdownlist - difficult. This is a dropdonwlinst where the user can select a value(easy, hard) but the value is not saved to the database, if I select a value. The strange thing I also have Country list, and that value is saved to the database.And If I put the values by hand in the database - for difficult the values are shown in the view
ModelVIew:
public RouteViewModel()
{
Countries = new List<SelectListItem>();
DifficultGrades = new List<SelectListItem>();
}
public int Id { get; set; }
[Required(ErrorMessage = "You need to give it a name")]
public string Name { get; set; }
public int SelectedValue { get; set; }
public int SelectedId { get; set; }
public IEnumerable<SelectListItem> Countries { get; set; }
public IEnumerable<SelectListItem> DifficultGrades { get; set; }
}
public class Difficult
{
[Key]
public int DifficultId { get; set; }
public string DifficultName { get; set; }
public virtual ICollection<Route> Routes { get; set; }
}
public class Route
{
[Key]
public int routeID { get; set; }
public string Name { get; set; }
public int? UserProfileID { get; set; }
public int? CountryID { get; set; }
public int? DifficultGradeID { get; set; }
public virtual UserProfile userProfile { get; set; }
public virtual Country country { get; set; }
public virtual Difficult difficult { get; set; }
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(RouteViewModel routeViewModel )
{
try
{
if (ModelState.IsValid)
{
var route = new Route();
UpdateRoute(route, routeViewModel);
db.Routes.Add(route);
db.SaveChangesAsync();
return RedirectToAction("Index");
}
}
catch (RetryLimitExceededException /* dex */)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
ViewBag.Id = new SelectList(db.countries, "Id", "country_name", routeViewModel.Id);
ViewBag.DifficultId = new SelectList(db.difficulties, "DifficultId", "DifficultName", routeViewModel.Id);
return View(new RouteViewModel());
}
and the update method:
public void UpdateRoute(Route route, RouteViewModel routeViewModel )
{
route.routeID = routeViewModel.Id;
route.Name = routeViewModel.Name;
route.CountryID = routeViewModel.Id;
route.DifficultGradeID = routeViewModel.Id;
// climb.country.country_name = ModelViewClimb.Name;
}
Thank you

Using Linq to pass data from one collection to another

I want to use LINQ to pass data from one custom collection to another. Its complicated because the collection has 2 sub collections.
Want to copy data to:
public class Quote
{
public int Id { get; set; }
public string Type { get; set; }
public virtual ICollection<Rate> Rates { get; set; }
}
public class Rate
{
public int Id { get; set; }
public virtual ICollection<Option> Options { get; set; }
}
public class Option
{
public int Id { get; set; }
public decimal Price { get; set; }
}
from:
public class Quote
{
public int QuoteId { get; set; }
public string Type { get; set; }
public string Destination { get; set; }
public List<RateSet> RateSets { get; set; }
}
public class RateSet
{
public int Id { get; set; }
public decimal ValueMin { get; set; }
public decimal ValueMax { get; set; }
public List<Option> Options { get; set; }
}
public class Option
{
public int Id { get; set; }
public string Name { get; set; }
public decimal? Price { get; set; }
}
I was getting somewhere with this but keeping hitting problems...
newQuotes = Quotes
.Select(x => new Quote() {
Id = x.QuoteId,
Rates = x.RateSets.Select( y => new Rate() {
Id = y.Id,
Options = y.Options.Select(z => new Option() {
Id = z.Id,
Price = z.Price
}).ToList(),....
to
Compiled without any errors
// to
public class Quote2
{
public int Id { get; set; }
public string Type { get; set; }
public virtual ICollection<Rate> Rates { get; set; }
}
public class Rate
{
public int Id { get; set; }
public virtual ICollection<Option2> Options { get; set; }
}
public class Option2
{
public int Id { get; set; }
public decimal Price { get; set; }
}
// from
public class Quote1
{
public int QuoteId { get; set; }
public string Type { get; set; }
public string Destination { get; set; }
public List<RateSet> RateSets { get; set; }
}
public class RateSet
{
public int Id { get; set; }
public decimal ValueMin { get; set; }
public decimal ValueMax { get; set; }
public List<Option1> Options { get; set; }
}
public class Option1
{
public int Id { get; set; }
public string Name { get; set; }
public decimal? Price { get; set; }
}
void Main()
{
var Quotes = new List<Quote1>();
var newQuotes = Quotes
.Select(x => new Quote2 {
Id = x.QuoteId,
Rates = x.RateSets == null ? null : x.RateSets.Select( y => new Rate {
Id = y.Id,
Options = y.Options == null ? null : y.Options.Select(z => new Option2 {
Id = z.Id,
Price = z.Price.Value
}).ToList()}).ToList()}).ToList();
}
I would make it a bit more modular:
newQuotes = Quotes.Select(x => new Quote
{
ID = x.QuoteID,
Type = x.Type,
Rates = ConvertRates(x.RateSets)
});
ConvertRates would use the same approach to create its sub objects and could either be a method or a Func:
ICollection<Rate> ConvertRates(IEnumerable<RateSet> oldRates)
{
return oldRates.Select(x => new Rate
{
ID = x.ID,
Options = ConvertOptions(x.Options)
}).ToList();
}
Basically, this is the same approach you used, just split up and readable.
I think what you need to do is define casting between each two corresponding classes, then cast one list into the other.
A simpler way may be to create methods in each class that would convert itself to the other type. Or if you don't want that kind of coupling, create a factory class that will do the conversion for you, one item at a time. Then use link to loop through and convert each item.
Like so:
public class Quote
{
public int Id { get; set; }
public string Type { get; set; }
public virtual ICollection<Rate> Rates { get; set; }
public static Quote FromData(Data.Quote input){
if (input == null) return null;
Quote output = new Quote()
{
Id = input.QuoteId,
Type = input.Type
};
output.Rates = (from i in input.RateSets
select Rate.FromData(i)).ToList();
}
}
public class Rate
{
public int Id { get; set; }
public virtual ICollection<Option> Options { get; set; }
public static Rate FromData(Data.RateSet input)
{
if (input == null) return null;
Rate output = new Rate()
{
Id = input.Id
};
output.Options = (from i in input.Options
select Option.FromData(i)).ToList();
return output;
}
}
public class Option
{
public int Id { get; set; }
public decimal Price { get; set; }
public static Option FromData(Data.Option input)
{
if (input == null) return null;
Option output = new Option()
{
Id = input.Id,
Price = input.Price ?? 0m
};
return output;
}
}
namespace Data {
public class Quote
{
public int QuoteId { get; set; }
public string Type { get; set; }
public string Destination { get; set; }
public List<RateSet> RateSets { get; set; }
}
public class RateSet
{
public int Id { get; set; }
public decimal ValueMin { get; set; }
public decimal ValueMax { get; set; }
public List<Option> Options { get; set; }
}
public class Option
{
public int Id { get; set; }
public string Name { get; set; }
public decimal? Price { get; set; }
}
}

Categories