Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have an model in my MVC application that contains som properties and som calculated properties. When i try to POST a new object of the model to database i get an error that my calculated properties cannot be null.
Here is my model:
public class OrderItem
{
public int orderItemId { get; set; }
[DataType(DataType.MultilineText)]
public string orderItemDescr { get; set; }
public string orderItemText { get; set; }
public double orderItemFixeedPrice { get; set; }
public virtual Order orderItemOrder { get; set; }
public virtual OrderItemType orderItemType { get; set; }
public virtual ICollection<Time> orderItemTime { get; set; }
public virtual ICollection<Material> orderItemMaterial { get; set; }
public OrderItem ()
{ }
public OrderItem (Order order)
{
this.orderItemOrder = order;
}
public string orderItemTypeDescr
{
get
{
return (this.orderItemType.orderItemTypeNumber.ToString() + " - " + orderItemDescr);
}
}
public double orderItemMaterialSum
{
get
{
return orderItemMaterial.Sum(m => m.materialItmPrice * m.materialItem);
}
}
public double orderItemTimeCount
{
get
{
return orderItemTime.Sum(t => t.timeItem);
}
}
public double orderItemTimeSum
{
get
{
return orderItemTime.Sum(t => t.timePrice * t.timeItem);
}
}
public double orderItemSum
{
get
{
return orderItemTimeSum + orderItemMaterialSum;
}
}
}
Error shows on properties: orderItemMaterialSum, orderItemTimeCount, orderItemTimeSum
these properties is only calculated as you seen and should not have values.
The problem comes only when i create an objekt and post it to database.
The reason for the error is that your properties in question are doubles and thus cannot be null. Three ways come to mind to address the problem:
Convert the properties in question to methods and re-factor your code
as necesesary.
Use a view model which only includes the properties you need (recommended)
Use the bind attribute to specify how binding is to be done when the model is posted (link)
Best practice is to use view models. Your view model might look something like the following:
public class OrderItemViewModel
{
public int orderItemId { get; set; }
[DataType(DataType.MultilineText)]
public string orderItemDescr { get; set; }
public string orderItemText { get; set; }
public double orderItemFixeedPrice { get; set; }
public virtual Order orderItemOrder { get; set; }
public virtual OrderItemType orderItemType { get; set; }
public virtual ICollection<Time> orderItemTime { get; set; }
public virtual ICollection<Material> orderItemMaterial { get; set; }
public string orderItemTypeDescr
{
get
{
return this.orderItemType.orderItemTypeNumber.ToString() + " - " + this.orderItemDescr;
}
}
}
Does this help?
Related
I got this models in my project:
public class Question
{
public int Id { get; set; }
public string Text { get; set; }
public QuestionType Type { get; set; }
public QuestionsTheme Theme { get; set; }
public string AnswerData { get; set; }
}
public class QuestionType
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
public TestStatus Status { get; set; }
public DateTime CreationDate { get; set; }
public DateTime Deadline { get; set; }
public DateTime FinishDate { get; set; }
public string CreatorLogin { get; set; }
public TestTheme Theme { get; set; }
}
public class QuestionsInTest
{
public int Id { get; set; }
public Test Test { get; set; }
public Question Question { get; set; }
}
public class AnswersOption
{
public int Id { get; set; }
public Question Question { get; set; }
public string Text { get; set; }
}
public class UserAnswer
{
public int Id { get; set; }
public string UserId { get; set; }
public Question Question { get; set; }
public Test Test { get; set; }
public string Data { get; set; }
public AnswerResult Result { get; set; }
}
Action on controller:
public ActionResult TestPage(int id, bool? isStarted)
{
var test = _testService.GetTest(id); //get test by Id
var qsts = _testService.GetQuestionsInTest(test); // get all questions in test
if (isStarted==null)
{
ViewBag.Qstns = qsts;
return View(test);
}
if (isStarted==true)
test.Status = Models.Enums.TestStatus.InProgress;
_testService.Update(test);
ViewBag.Qstns = qsts;
ViewBag.QstOptions = _answerService.GetAnswersOptions(qsts);
//get all answer options for every question
return View(test);
}
TestPage view render depends on test.Status. If Status is "inProgress", Test page with questions renders. This part is that im intrerested in.
...
...
...
if (Model.Status == OnlineTestingProject.Models.Enums.TestStatus.NotStarted)
{
<h1>Test is not started</h1>
<b>Creation date: </b>
<b>#Model.CreationDate</b>
<b>Test creator: </b>
<b>#Model.CreatorLogin</b>
using (Html.BeginForm("TestPage", "Student", FormMethod.Post))
{
#Html.Hidden("id", #Model.Id)
#Html.Hidden("isStarted", true)
<input type="submit" value="Begin test" />
}
}
if (Model.Status == OnlineTestingProject.Models.Enums.TestStatus.InProgress)
{
int i = 0;
<h1>les gooo</h1>
foreach (Question qst in ViewBag.Qstns)
{
<div>
#{
<b>Question number : #i</b>
<p>#qst.Text</p>
foreach (AnswersOption opt in ViewBag.QstOptions)
{
if (opt.Question == qst)
{
if (opt.Question.Type.Name == "Single")
{
...
}
if (opt.Question.Type.Name == "Multi")
{
...
}
...
}
}
}
<hr />
</div>
i++;
}
}
}
The idea is:
User open a Test Page. Test has a set of questions. Every question has specific type (like usual with one right answer, with multiple right answers, question with typing field end so on). Every question also has a set of answers variants. Questions with one right answer will have radio buttons for options, qustions with multiple options will have comboboxes, input for amother and so on. User should fill the answer and on sumbit button (e. g. Finish test) all answers given by user should be compared with right answer.
The question is:
How to organize it on view side. And how to agregate it on controller side.
I got some thoughts about one big modelView or dictionaries but my brain in already melting so i would be glad to get some kick in the right direction.
UPD. I know one way (or the only way) to do it is to fill ViewModel. But i have no idea how this model should looks like. Is the best way to create some ViewModel and if it is, then how to store all my answers and its options and how to compare given answer with right one properly
Firstly, apologies if this seems basic, I am new to C#/dotnet and if the answer to this questions is somewhere obvious please point me in the right direction.
I have a DTO class with the following code
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonImagesListView> LessonImages { get; set; }
public List<LessonInstructionCardListView> InstructionCards { get; set; }
}
public class LessonImagesListView
{
public long Id { get; set; }
public string Title { get; set; }
public ImageDetailView Image { get; set; }
public LessonImagesListView()
{
Image = new ImageDetailView();
}
}
public class LessonInstructionCardListView
{
public long Id { get; set; }
public string Instructions { get; set; }
}
So I have 2 distinct types of object that I attach to the lesson and send to the frontend.
I will add that in the future I might have 6 different types of object.
These Images, or Instructions are also going to be displayed in a certain order on the front end so instead of sending them all separately I wanted to combine them all and send them in a new List LessonAssetsListView for example.
How can i create Lists in a DTO that combine 2 other lists ?
OR ... is this something I even need to do here ... and can i just do all this in my service.
Help appreciated.
You could simply define a type that composes both your existing and send a List of them
public class LessonAsset
{
public LessonImagesListView Image {get;set; }
public LessonInstructionCardListView Instruction {get;set;}
}
and then
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonAsset> LessonAssets { get; set; }
}
I was working on my project and I've come across this error that makes me abit frustrated for no reason:
[TheProblem][1]
[1]: https://i.stack.imgur.com/9Ajtn.png
I have been looking for many ways to solve this even on this very website but none worked so far for C# and Xaml. I am attempting to get JSON files into UPF to look like GUI.
My Vehicle Class:
public class Vehicle
{
[JsonPropertyName("make")]
public string Make { get; set; }
[JsonPropertyName("model")]
public string Model { get; set; }
[JsonPropertyName("VIN")]
public string VIN { get; set; }
[JsonPropertyName("CarType")]
public string CarType { get; set; }
[JsonPropertyName("Seatingcapacity")]
public int Seatingcapacity { get; set; }
[JsonPropertyName("DateObtained")]
public string DateObtained { get; set; }
[JsonPropertyName("NumOfMiles")]
public int NumOfMiles { get; set; }
[JsonPropertyName("InspectionNum")]
public int InspectionNum { get; set; }
[JsonPropertyName("InspectionTech")]
public string InspectionTech { get; set; }
[JsonPropertyName("InspectionDate")]
public string InspectionDate { get; set; }
[JsonPropertyName("InspectIssues")]
public string InspectIssues { get; set; }
[JsonPropertyName("RepairDiscard")]
public string RepairDiscard { get; set; }
[JsonPropertyName("EstPrice")]
public int EstPrice { get; set; }
[JsonPropertyName("EstimatedBy")]
public string EstimatedBy { get; set; }
[JsonPropertyName("EstimatedDate")]
public string EstimatedDate { get; set; }
[JsonPropertyName("SalePrice")]
public int SalePrice { get; set; }
[JsonPropertyName("SalesPerson")]
public string SalesPerson { get; set; }
[JsonPropertyName("SalesDate")]
public string SalesDate { get; set; }
[JsonPropertyName("NegotiatedPrice")]
public string NegotiatedPrice { get; set; }
[JsonPropertyName("NegotiatedPriceApproved")]
public string NegotiatedPriceApproved { get; set; }
}
public class Root
{
[JsonPropertyName("Vehicle")]
public List<Vehicle> Vehicle { get; set; }
}
public class VehicleManager
{
public static async Task<Root> GetVehicles()
{
string target = "Vechile.json";
Root vehicleJson = JsonConvert.DeserializeObject<Root>(target);
return vehicleJson;
}
}
My Vehicle JSON:
{
"make": "Audi",
"model": "A4",
"vin": "1B4HR28N41F524347",
"carType": "Sedan",
"Seatingcapacity": 4,
"DateObtained": "05/15/2010",
"NumOfMiles": 434567,
"InspectionNum": 312345,
"InspectionTech": "Windows",
"InspectionDate": "06/05/2016",
"InspectIssues": "No Issue",
"RepairDiscard": "No Discard",
"EstPrice": 700000,
"EstimatedBy": "Sannaha Vahanna",
"EstimatedDate": "04/27/2010",
"SalePrice": 500000,
"SalesPerson": "Sannaha Vahnna",
"SalesDate": "05/15/2010",
"NegotiatedPrice": "$45,000",
"NegotiatedPriceApproved": "Sannaha Vahnna"
}
}```
As well, my C#
```public sealed partial class MainPage : Page
{
public MainPage()
{
var Vehicles = VehicleManager.GetVehicles();
this.InitializeComponent();
}
private void VehicleGUI_ItemClick(object sender, ItemClickEventArgs e)
{
var vehicle= (Vehicle)e.ClickedItem;
this.Frame.Navigate(typeof(VehicleDetails), vehicle);
}
}```
What to do?
Look at the error message it's giving you. It says the unexpected character is 'V' at line 0 position 0. My guess is the data being passed is not actually the JSON data you think it is - perhaps it's some kind of string representation of a Vehicle (only guessing on that part from the 'V').
The best way to troubleshoot is throw your data being serialized into a local variable and set a break point right before you call the method to serialize. That way you can see exactly what is getting passed.
You may actually want to check out this question, you may be having a similar issue.
EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?
My database table for buildings stores the building type as a code. In a separate lookup table the description for that code is stored.
How should I design my ViewModel and where will I need to make the call to get the associated description value?
I sort of can see one option. I want to know if there is a better option.
BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
Then in my view
code...
<p>#MyService.GetDescription(Model.BuildingTypeCode)</p>
...code
Am I incorrect in the way I am thinking? if I do the above I create a dependency in my View to the service?
Update 1
Working through some of the solutions offered. I seem to run into another issue. I can't access the constructor of each building directly...
public ViewResult Show(string ParcelId)
{
var result = _service.GetProperty(ParcelId);
var AltOwners = _service.GetAltOwners(ParcelId);
var Buildings = _service.GetBuildings(ParcelId);
ParcelDetailViewModel ViewModel = new ParcelDetailViewModel();
ViewModel.AltOwnership = new List<OwnerShipViewModel>();
ViewModel.Buildings = new List<BuildingViewModel>();
AutoMapper.Mapper.Map(result, ViewModel);
AutoMapper.Mapper.Map<IEnumerable<AltOwnership>, IEnumerable<OwnerShipViewModel>>(AltOwners,ViewModel.AltOwnership);
AutoMapper.Mapper.Map<IEnumerable<Building>, IEnumerable<BuildingViewModel>>(Buildings, ViewModel.Buildings);
ViewModel.Pool = _service.HasPool(ParcelId);
ViewModel.Homestead = _service.IsHomestead(ParcelId);
return View(ViewModel);
}
public class ParcelDetailViewModel
{
public IEnumerable<OwnerShipViewModel> AltOwnership { get; set; }
//public IEnumerable<ValueViewModel> Values { get; set; }
public IEnumerable<BuildingViewModel> Buildings { get; set; }
//public IEnumerable<TransferViewModel> Transfers { get; set; }
//public IEnumerable<SiteAddressViewModel> SiteAddresses { get; set; }
public string ParcelID { get; set; }
//public string ParcelDescription { get; set; }
//public int LandArea { get; set; }
//public string Incorporation { get; set; }
//public string SubdivisionCode {get;set;}
public string UseCode { get; set; }
//public string SecTwpRge { get; set; }
//public string Census { get; set; }
//public string Zoning { get; set; }
public Boolean Homestead {get;set;}
//public int TotalBuildingArea { get; set; }
//public int TotalLivingArea { get; set; }
//public int LivingUnits { get; set; }
//public int Beds { get; set; }
//public decimal Baths { get; set; }
public short Pool { get; set; }
//public int YearBuilt { get; set; }
}
My understanding is that the view model is meant for display ready data. I think the real problem here is putting model dependent logic into the view.
You can do your service lookup but keep that code in the controller. The view model should be considered display ready (save for some formatting).
class BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
and then do the lookup before you render:
public ActionResult Building()
{
var typeCode = // get from original source?
var model = new BuildingViewModel
{
BuildingTypeCode = MyService.GetDescription(typeCode)
};
return View("Building", model);
}
Having come from a long line of JSP custom tags I dread having any code hidden in the view layout. IMO, that layer should be as dumb as possible.
I would recommend having a helper that does that, or a DisplayTemplate
public class ViewHelpers
{
public static string GetDescription(string code)
{
MyService.GetDescription(Model.BuildingTypeCode);
}
}
or
#ModelType string
#Html.DisplayFor("",MyService.GetDescription(Model.BuildingTypeCode));
More info on templates: http://www.headcrash.us/blog/2011/09/custom-display-and-editor-templates-with-asp-net-mvc-3-razor/
Both of these approaches introduce a dependency on your service but you can test/change them in one single place, instead of the whole application (plus the usage looks cleaner).