If I construct a View Model with a List like this:
public class ProductsViewModel
{
public bool ProductBool { get; set; }
public string ProductString { get; set; }
public int ProductInteger { get; set; }
public List<Product> ProductList { get; set; }
}
it works fine. But I've seen code that constructs a similar Model like so:
public class ProductsViewModel
{
public bool ProductBool { get; set; }
public string ProductString { get; set; }
public int ProductInteger { get; set; }
public List<Product> ProductList { get; set; }
public ProductsViewModel()
{
this.ProductList = new List<Product>();
}
}
What does the extra contructor element actually do?
When you create an object of the class ProductsViewModel with the statement:
ProductsViewModel obj = new ProductsViewModel();
It automatically instantiate the ProductList. The values in obj now are:
ProductBool = false;ProductString = null;ProductInteger = 0;ProductList = new ProductList();
If you write obj.ProductList.Count() it will give 0
If you remove this constructor or the statement inside the constructor and create object of Class ProductsViewModel as created above. The values in obj will be:
ProductBool = false;ProductString = null;ProductInteger = 0;ProductList =null
If you write obj.ProductList.Count() it will give
Exception of NullReference
Related
I have a problem with generic types in X++. I need to deserialize a JSON list yet everything I tried failed. Like using IEnumerables and JsonSerializer(does it find only AX classes and can't see references library classes?).
My helper class is in a C# library and I only need to get access to values inside the response JSON that are in list. How can I archive this in X++?
//X++
defaultException defaultException= new defaultException();
defaultException= JsonConvert::DeserializeObject(response, defaultException.GetType()); <- this gives is correct yet I cant use the values in the list
//values = FormJsonSerializer::deserializeCollection(classnum(List), response, Types::Class, 'defaultException');
// C#
public class defaultException
{
public MyException exception { get; set; }
}
public class MyException
{
public string serviceCtx { get; set; }
public string serviceCode { get; set; }
public string serviceName { get; set; }
public string timestamp { get; set;}
public string referenceNumber { get; set; }
public List<exceptionDetailList> exceptionDetailList { get; set; }
}
public class exceptionDetailList
{
public int exceptionCode { get; set; }
public string exceptionDescription { get; set; }
}
Found a solution. If we have another list in this list we need to recreate the enumerator in loop again and again as needed.
defaultException defaultException = new defaultException();
defaultException = JsonConvert::DeserializeObject(batch, defaultException.GetType());
System.Collections.IEnumerable exceptionList = defaultException.exception.exceptionDetailList;
System.Collections.IEnumerator enumerator = exceptionList.GetEnumerator();
while (enumerator.MoveNext())
{
exceptionDetailList exceptionDetailList = new exceptionDetailList();
exceptionDetailList = enumerator.Current;
}
i have this controller method that return an array of objects
public async Task<ActionResult<List<AllClientsDataModelDb>>> GetAll()
{
var ReturnValue = new List<AllClientsDataModelDb>();
ReturnValue = await Clda.GetClients(new { cm = 1 });
return (ReturnValue);
}
here is the code of AllClientsDataModelDb class
public class AllClientsDataModelDb
{
public long IDCLIENT { get; set; }
public string CL_CODE { get; set; }
public string CL_NOM { get; set; }
public string CL_ADRESSE { get; set; }
public string CL_CODEPOS { get; set; }
public string CL_VILLE { get; set; } = null;
public int CL_ETATCOMPTE { get; set; }
public int CL_AlerteCompta { get; set; }
}
but the result of that method (in browser) does not respect the case sensitivity of the class properties
Example :
[{"idclient":1,"cL_CODE":"1","cL_NOM":"EUROPEQUIPEMENTMysql","cL_ADRESSE":"ModifSoft","cL_CODEPOS":"44","cL_VILLE":"STDENIS","cL_ETATCOMPTE":1,"cL_AlerteCompta":0},
{"idclient":2,"cL_CODE":"2","cL_NOM":"A UTOMATISMES-SERVICESzzzz","cL_ADRESSE":null,"cL_CODEPOS":"97420","cL_VILLE":"LEPORT","cL_ETATCOMPTE":1,"cL_AlerteCompta":0},
what i'm doing wrong ?
You need to create your own Json Profile Formatter by inheriting from JsonOutputFormatter.
public class PascalCaseJsonProfileFormatter : JsonOutputFormatter
{
public PascalCaseJsonProfileFormatter() : base(new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() }, ArrayPool<char>.Shared)
{
SupportedMediaTypes.Clear();
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse
("application/json;profile=\"https://en.wikipedia.org/wiki/PascalCase\""));
}
}
Then modify your Startup.cs file's ConfigureServices Method like this.
services.AddMvc()
.AddMvcOptions(options =>
{
options.OutputFormatters.Add(new PascalCaseJsonProfileFormatter());
});
Try this, it should work.
Could somebody please provide an example of how to combine two models within one view?
Currently I have a page called RecordCard which contains:
#model IEnumerable<WebApplication1.Models.Weight>
This is provided by the following code in the AccountController:
public ActionResult RecordCard()
{
var UserId = User.Identity.GetUserId();
var weightModel = from m in db.Weights where m.UserId == UserId select m;
return View(weightModel);
}
The RecordCard page also contains a form which is bound to the following class:
public class AddWeightModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "Stone")]
public Nullable<short> Stone { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Pound")]
public Nullable<short> Pound { get; set; }
}
However, these are two individual models with different purposes, so how do I combine to a single model that contains an IEnumerable list and set of form elements that will ultimately post to the AccountController correctly to add a record to the database using the following code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RecordCard(Weight Model)
{
if (ModelState.IsValid)
{
using (WebApplication1Entities db = new WebApplication1Entities())
{
Weight weight = new Weight();
weight.UserId = User.Identity.GetUserId();
weight.Stone = Model.Stone;
weight.Pound = Model.Pound;
weight.Date = System.DateTime.Now;
db.Weights.Add(Model);
db.SaveChanges();
}
}
return View(Model);
}
I have included the Weight class below:
public partial class Weight
{
public int Id { get; set; }
public string UserId { get; set; }
public Nullable<short> Stone { get; set; }
public Nullable<short> Pound { get; set; }
public Nullable<System.DateTime> Date { get; set; }
}
Also here is the WebApplication1Entities class which declares the Weight table as Weights:
public partial class WebApplication1Entities : DbContext
{
public WebApplication1Entities()
: base("name=WebApplication1Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Weight> Weights { get; set; }
}
Please explain what needs to be modified and how, no matter what I try to read, follow and implement, I seem to be missing something.
Any help would be much appreciated :-)
I would say this is good example of using ViewModel here. I would suggest something like -
Create ViewModel with the composition of the two classes
public class AddWeightModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "Stone")]
public Nullable<short> Stone { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Pound")]
public Nullable<short> Pound { get; set; }
}
....
public partial class Weight
{
public int Id { get; set; }
public string UserId { get; set; }
public Nullable<short> Stone { get; set; }
public Nullable<short> Pound { get; set; }
public Nullable<System.DateTime> Date { get; set; }
}
.....
public class WeightViewModel
{
public IList<AddWeightModel> AddWeightModel { get; set; }
public Weight Weight { get; set; }
}
Then change your view to accept the view models -
#model WeightViewModel
Finally modify your controller to cope with the change -
public ActionResult RecordCard()
{
var UserId = User.Identity.GetUserId();
var weightModel = from m in db.Weights where m.UserId == UserId select m;
var viewModel = new WeightViewModel
{
Weight = weightModel,
AddWeightModel = new List<AddWeightModel>(){}
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RecordCard(WeightViewModel viewModel)
{
Weight Model = viewModel.Weight;
if (ModelState.IsValid)
{
using (WebApplication1Entities db = new WebApplication1Entities())
{
Weight weight = new Weight();
weight.UserId = User.Identity.GetUserId();
weight.Stone = Model.Stone;
weight.Pound = Model.Pound;
weight.Date = System.DateTime.Now;
db.Weights.Add(Model);
db.SaveChanges();
}
}
return RedirectToAction("RecordCard");
}
I've tackled this before, can came to an elegant solution.
First, you'd want to setup your main classes to send, as well as a 'holder' class to store them to eventually send to a view.
As you probably found out, this is because a view can't have multiple models sent to it.
public class WebsiteTheme
{
public string Color { get;set; }
public string Title { get;set; }
public WebsiteTheme() {
Color = "blue";
Title = "test website";
}
}
public class User
{
public string Name { get;set; }
public string Gender { get;set; }
public User() {
Name = "Anonymous";
Gender = "Unspecified";
}
}
public class ToPage
{
public WebsiteTheme WebsiteTheme{ get; set; }
public User User { get; set; }
public ToPage() {
websiteTheme = new WebsiteTheme();
user = new User();
}
}
This will allow you to send any amount of classes to your page.
Then, in your controller, you'd want to populate those classes. Make sure to initialise them all first, then set the populated classes to your holder class.
WebsiteTheme websiteTheme = new WebsiteTheme();
websiteTheme.Color = "orange";
User user = new User();
user.Name = "Darren";
ToPage toPage = new ToPage();
toPage.User = user;
toPage.WebsiteTheme = websiteTheme;
return View(toPage);
In your view, you'd call them in any way you want to. But make sure to use HolderModel.SpecifiedModel in every case.
#model WebApplication1.Models.ToPage
#Html.DisplayFor(model => model.User.Name)
I did a compound model like this:
public class CompoundModel
{
public SearchModel SearchModel { get; set; }
public QueryResultRow ResultModel { get; set; }
}
public class QueryResultRow
{
[DisplayName("Id")]
public long id { get; set; }
[DisplayName("Importdatum")]
public System.DateTime importdate { get; set; }
[DisplayName("Mandant")]
public int indexBMClient { get; set; }
}
public class SearchModel
{
[Required]
[DataType(DataType.Date)]
[Display(Name = "Zeitraum von")]
public DateTime dateFrom { get; set; }
[Display(Name = "Terminal-ID")]
public string tid { get; set; }
[Display(Name = "Belegnummer")]
public string receiptnumber { get; set; }
}
In the view header:
#model MyProject_aspmvc.Models.CompoundModel
And get data access from the SearchModel, for example:
model => model.SearchModel.tid
and data access from the ResultModel, for example:
model => model.ResultModel.importdate
I've been searching this without any luck on how to resolve. I have a list of available departments that can be used within my stores. Since stores vary, some departments may not exist and I want to keep track of how much shelving space each department has for each store. What's the best way to create this?
Here's my model:
public class Store
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; } //StoreNumber
public virtual List<StoreDepartment> StoreDepartments { get; set; }
}
public class StoreDepartment
{
[Key]
public int ID { get; set; }
public int StoreID { get; set; }
public Department Department { get; set; }
public int ShelvingLinealFT { get; set; }
}
public class Department
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; } //DepartmentNumber
public string Name { get; set; }
public bool InActive { get; set; }
}
I've already populated my Department tables, but when I attempt to save a StoreDepartment object, I get an error stating that it can't insert a row since its trying to create a duplicate key. It's like it's trying to create a new record.
Any help would be appreciated.
Here's the code for my DbContext:
public class StoresRepository:DbContext
{
public DbSet<Store> Stores { get; set; }
public DbSet<StoreDepartment> StoreDepartments { get; set; }
public DbSet<Department> Departments { get; set; }
}
Here is my Save method:
/// <summary>
/// Saves a StoreDepartment Object to the store("dept.storeid")
/// Adds a new record if ID is 0
/// </summary>
/// <param name="dept"></param>
/// <returns></returns>
public bool Save(StoreDepartment dept)
{
bool retval = false;
try
{
using (var db = new StoresRepository())
{
if (dept.ID.Equals(0))
{
//Add Store Department
db.StoreDepartments.Add(dept);
}
else
{
//this is an update
StoreDepartment department = db.StoreDepartments.Where(p => p.ID.Equals(dept.ID)).FirstOrDefault();
department.Department = dept.Department;
department.ShelvingLinealFT = dept.ShelvingLinealFT;
}
int rowsupdated = db.SaveChanges();
retval = true;
}
}
catch (Exception ex)
{
Utils.Trace(string.Format("StoresContext.cs: StoreDepartments.Save(). ID:{1}. Exception: {0}", ex, dept.ID), Utils.ErrorTypes.Error);
}
return retval;
}
You probably change the state of the Department to added when you add the StoreDepartment object. Something like this:
using(var db = new MyContext())
{
var storeDepartment = new StoreDepartment();
storeDepartment.StoreId = storeId;
storeDeparemtent.Department = department;
db.StoreDepartments.Add(storeDepartment); // also marks Department as added
db.SaveChanges();
}
The solution is to move up the line where you add the object:
using(var db = new MyContext())
{
var storeDepartment = new StoreDepartment();
db.StoreDepartments.Add(storeDepartment);
storeDepartment.StoreId = storeId;
....
}
You can also add a DepartmentId to the StoreDepartment class and set its value, as you do with StoreId. Together with the Department property this is called a foreign key association.
I figured it out.
Here are the correct models:
public class StoreDepartment
{
[Key]
public int ID { get; set; }
public int DepartmentID { get; set; }
public virtual Department Department { get; set; }
public int ShelvingFootage { get; set; }
}
public class Department
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public virtual ICollection<StoreDepartment> StoreDepartments { get; set; }
}
Using Affluent API, I setup my relationships as follows:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<StoreDepartment>().HasRequired(d => d.Department);
modelBuilder.Entity<Department>().HasMany(d => d.StoreDepartments);
}
Once I had this setup, one of the main issues I had was with populating the object.
Normally, you would do the following:
StoreDepartment sd = new StoreDepartment();
sd.Department = new Department(){
ID = 302,
Name = "Deli"
};
sd.ShelvingFootage = 100;
However when trying to save this object, Entity would attempt to add a new record in the Department table which of course would throw an exception due to a violation in the primary key.
The trick was to not update this directly and to build my StoreDepartment object as follows:
StoreDepartment sd = new StoreDepartment();
sd.DepartmentID = 302;
sd.ShelvingFootage = 100;
By doing this, you are only updating the foreign key for the StoreDepartment.Department object.
i am having a simple demo class like this...
Employee
public class Employee
{
public string Name { get; set; }
public string Email { get; set; }
}
one more class AddressDetails
public class AddressDetails
{
public string Address1 { get; set; }
public string City { get; set; }
public string State { get; set; }
}
one more EmpAdd
public class EmpAdd
{
public ICollection<Employee> Employees { get; set; }
public ICollection<AddressDetails> AddressDetails { get; set; }
}
ok, when i am passing some values in class like this..
Employee newEmp = new Employee();
newEmp.Email = "temp#gmail.com";
newEmp.Name = "Judy";
AddressDetails newAddress = new AddressDetails();
newAddress.Address1 = "UK";
newAddress.City = "London";
newAddress.State = "England";
all works fine...
but when i am trying to add this two in EmpAdd it gives me error "Object reference not set to an instance" please help ...this is just a dummy .. i have 7 entities in which i am facing the same problem....
EmpAdd emp = new EmpAdd();
emp.Employee.Add(newEmp);
emp.AddressDetails.Add(newAddress);
emp.Employee and emp.AddressDetails are not instantiated. You need to create a constructor which instantiates them
public class EmpAdd
{
public ICollection<Employee> Employees { get; set; }
public ICollection<AddressDetails> AddressDetails { get; set; }
public EmpAdd()
{
Employees = new List<Employee>();
AddressDetails = new List<AddressDetails>();
}
}
Your ICollection property is never initialized. The auto properties implement a field behind your property, but it still needs to be assigned to.
I suggest making your property read-only (get rid of the set), implement the field behind it yourself, and initialize it on declaration:
private List<Employee> _employees = new List<Employee>();
public ICollection<Employee> Employees {
get
{
return _employees;
}
}
What #Adrian Iftode means is this:
EmpAdd emp = new EmpAdd();
emp.Employee = newEmp;
emp.AddressDetails = newAddress;
emp.Employee.Add(newEmp);
emp.AddressDetails.Add(newAddress);
This should fix this.
Anyway, stick to #Menno van den Heuvel's suggestion.