I have a model called Project
public class Project
{
[Key]
public int ID { set; get; }
public string Title { set; get; }
public string Image { set; get; }
public double? gained { set; get; }
}
I use this model with two stored procedures one returns all the properties and the other without the property gained. And I got this error
The data reader is incompatible with the specified 'Test.Models.Project'. A member of the type, 'Gained', does not have a corresponding column in the data reader with the same name.
I don't want to write separate models for each stored procedure.
How to solve that please ?
The datareader is kind of dumb in the sense that it will only match what was sent back to it. If a column is missing, it fails, as you can see.
The easiest way to solve this would be to update your second SELECT statement in your stored procedure to pass back a column named gained.
SELECT ID, Title, Image, NULL as gained FROM table
Here, we are passing back no data (NULL) as the gained column. This should make the data reader happy, keep you from needing multiple models and not send back any extra data.
The other possibility would be to use inheritance in your models. Have a base model that does not include gained, and have a second model that inherits from the base model that does include gained.
public class ProjectBase
{
[Key]
public int ID { set; get; }
public string Title { set; get; }
public string Image { set; get; }
}
public class ProjectGained : ProjectBase{
public double? gained { set; get; }
}
Related
I am working on an ASP.Net MVC Website.
I have a table called animal, which is created based of this class using Entity Framework code first:
public class Animal
{
public int AnimalId { get; set; }
public string AnimalName { get; set; }
public int NoOfLegs { get; set; }
public int FlyingSpeed { get; set; }
public int RunningSpeed { get; set; }
}
Now I have my AnimalRepository that reads this info from the DB and pass it to my ViewModel (My Domain Classes are different from my ViewModel and I am using ModelReader, ModelWriter and AutoMapper to Map my domain model into my view model as explained here). I have this generic interface in my ViewModel:
public interface IAnimalModel
{
int AnimalId { get; set; }
string AnimalName { get; set; }
int NoOfLegs { get; set; }
}
And I have these two classes in my ViewModel:
public class DogModel: IAnimalModel
{
public int AnimalId { get; set; }
public string AnimalName { get; set; }
public NoOfLegs { get; set; }
public int RunningSpeed { get; set; }
}
public class EagleModel: IAnimalModel
{
public int AnimalId { get; set; }
public string AnimalName { get; set; }
public NoOfLegs { get; set; }
public int FlyingSpeed { get; set; }
}
Now I have one Animal Controller that uses AnimalRepositoy to get the data from DB, and maps it to the correct ViewModel.
I want to bind my View to IAnimalModel interface so that I can pass different animals to the same View.
In my View, I want to use Razor Code to display certain properties based on Animal Model type, something like this:
#if (typeof(Model) == typeof(EagleModel)) {
Html.EditorFor(model => model.FlyingSpeed)
}
#if (typeof(Model) == typeof(DogModel)) {
Html.EditorFor(model => model.RunningSpeed)
}
I have been thinking about this for a long time and I am not sure if this is a good solution? I have quite a few different Animal types with a lot of common properties, so don't really like the idea of creating one Table for each different animal.
I thought it's better to map them to correct type in my ViewModel...
I am not really sure if binding my ViewModel to IAnimalModel interface is a good idea? As I need to check the model type before displaying certain properties.
Another disadvantage is that in my DB, I don't know which type of animal each row contains... I am thinking maybe of I have to add a ViewModelType column to my Animal table, but again I am not sure if this is a good solution?
I think the problem is much simpler to be honest.
You're talking about a lot of animals but you could think in terms of types and then everything simplifies.
So based on some very quick research, you have 6 animal types:
Invertebrates
Fish
Amphibians
Reptiles
Birds
Mammals
You can probably get away with less. So if you look at your problem from this point of view, now you don't have that many different types to look at.
So, have an animal type enum and use that to differentiate the fields you are displaying.
In terms of database, I would not go with one table and null fields as that complicates everything. Either create a base one with whatever is common and a separate one for each type, or go with a Nosql db and save one type data per row.
Finally I don't really think that using a base interface gives you anything. You still have to repeat the fields in every class that implements it and you're not achieving anything in terms of simplification. If you instead go with a base abstract class then at least you don't have to repeat the same properties everywhere and your classes are now smaller and reflect the differences properly.
I'm trying to map a relation N:N for an entity which has some other information. In fact, to brief you better I have the following scenario:
A user can apply as many times as he wants for a exam and this application saves the final result. (That's why i didn't map the key with this to classes)
Looking for this over the internet I found some solutions regarding the creation of Id properties to save information about the Foreign Key besides the property itself. As I don't agree with this solution because I don't believe that we have to change our Model to satisfy ORM needs, I would like to know if you guys have another solution for me.
The following code is a piece of the classes I want to map. Currently, I didn't configure collections in the main classes and when I try to save the application I receive a key violation in the database because it tries to save the User/Exam in the database again.
Sorry if it is a silly question and thanks for your help.
public class User
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class Exam
{
public int Id { get; set; }
public string Description { get; set; }
}
public class Application
{
public int Id { get; set; }
public virtual User User { get; set; }
public virtual Exam Exam { get; set; }
public int Result { get; set; }
}
I have 2 models like this.
public partial class Question
{
public int QuestionId { get; set; }
public string QuestionText { get; set; }
public string Ans1 { get; set; }
public string Ans2 { get; set; }
public string Ans3 { get; set; }
public string Ans4 { get; set; }
}
public partial class UserAnswer
{
public int UserAnsId { get; set; }
public Nullable<int> QuestionId { get; set; }
public Nullable<int> UserId { get; set; }
public Nullable<int> AnsVal { get; set; }
}
As you can see QuestionId is in both the models. How can I render it in view. There are multiple questions. Question Moldel has data in initial run but UserAnswer doesn't.
How can I combine these 2 models so that I can use it as IEnumerable in view. Ans1,Ans2,Ans3,Ans4 has text and AnsVal in UserAnswer will get its value from Raiobutton.
make a combine class like below..i am not sure this is perfect or not..any suggestions are acceptable.
public class QuestionAnswerViewModel
{
public Question Question {get;set;}
public ICollection<UserAnswer> Answers {get;set;}
}
You want to create a ViewModel that represents the combined model objects. This keeps things clean, your model is just that, the model, what gets passed to the view can be the model but in many cases the concept of a ViewModel will make things easier to design while keeping your code loosely coupled and clean. This also keeps things that are not important to the View out of the equation aka particular properties in your model such as maybe a CreatedDate should not be passed to the View, especially since View requests will pass back the value as null since it is not being used in the view and thus not populated on postback. This could lead to you updating the database with a null value for CreatedDate simply because it was not used in the View.
Maybe you have a Model class library in your solution? If you do, create another class library called MyNamespace.Web.ViewModels or something like that. Also you should look into using a tool like AutoMapper that will populate the ViewModel on View request to the Controller and populate the model on View postback to the controller.
I am trying to send a simple object (AjaxSubmission) from a form to a Web API controller used to edit tables.
AjaxSubmission always has the same fields. One field, "data" refers to another simple object with accessors for the specific table (Employees or Vendors examples below).
public class AjaxSubmission
{
public string action { get; set; }
public string table { get; set; }
public string id { get; set; }
// ...
//// The following may be any other custom class
public Employees data { get; set; } // Could be Vendors or whatever
}
// Stored in AjaxSubmission (or so I hope)
public class Employees
{
public string name { get; set; }
public float salary { get; set; }
public long id { get; set; }
}
// Stored in AjaxSubmission
public class Vendors
{
public string dba { get; set; }
public int accountNum { get; set; }
public int zipcode { get; set; }
}
My controller gets the data like so:
public EditorServerResponse Put(AjaxSubmission ajaxSubmission = null) {
// Handle the data
}
When I make "data" an Object or Dynamic, it shows up as an empty object. I can't "as" it to Employees or Vendors because it doesn't store anything.
I suspect this is a limitation of the serializer. MVC4 uses JSON.NET for JSON, but the data is sent as "Content-Type: application/x-www-form-urlencoded; charset=UTF-8".
I cannot easily change the way data is sent because that is how the Datatables editor plug-in does its business. I think it's a reasonable way to send data and a reasonable problem for .NET to be able to handle.
I can get the data I need if I make a distinct class for each data type that AjaxSubmission might contain, but each would be a duplicate other than one line of code. That horribly violates the DRY principle.
My question is: How can I send AjaxSubmission without Repeating Myself? Is .NET capable of such a thing?
Edit:
Fiddler says the data looks like:
action edit
table
id row_4
data[amu] 49
data[chemicalFormula] BF2
data[commonName] Boron difluoride
data[status] Y
data[notes]
The raw data is:
action=edit&table=&id=row_4&data%5Bamu%5D=49&data%5BchemicalFormula%5D=BF2&data%5BcommonName%5D=Boron+difluoride&data%5Bstatus%5D=Y&data%5Bnotes%5D=
(This is different from my simplified examples but similar)
I have a DbDataController which delivers a List of Equipment.
public IQueryable<BettrFit.Models.Equipment> GetEquipment() {
var q= DbContext.EquipmentSet.OrderBy(e => e.Name);
return q;
}
In my scaffolded view everything looks ok.
But the Equipment contains a HashSet member of EquipmentType. I want to show this type in my view and also be able to add data to the EquipmentType collection of Equipment (via a multiselect list).
But if I try to include the "EquipmentType" in my linq query it fails during serialisation.
public IQueryable<BettrFit.Models.Equipment> GetEquipment() {
var q= DbContext.EquipmentSet.Include("EquipmentType").OrderBy(e => e.Name);
return q;
}
"Object Graph for Type EquipmentType Contains Cycles and Cannot be Serialized if Reference Tracking is Disabled"
How can I switch on the "backtracking of references"?
Maybe the problem is that the EquipmentType is back-linking through a HashSet? But I do not .include("EquipmentType.Equipment") in my query. So that should be ok.
How is Upshot generating the model? I only find the EquipmentViewModel.js file but this does not contain any model members.
Here are my model classes:
public class Equipment
{
public Equipment()
{
this.Exercise = new HashSet<Exercise>();
this.EquipmentType = new HashSet<EquipmentType>();
this.UserDetails = new HashSet<UserDetails>();
}
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Picture { get; set; }
public string Link { get; set; }
public string Producer { get; set; }
public string Video { get; set; }
public virtual ICollection<EquipmentType> EquipmentType { get; set; }
public virtual ICollection<UserDetails> UserDetails { get; set; }
}
public class EquipmentType
{
public EquipmentType()
{
this.Equipment = new HashSet<Equipment>();
this.UserDetails = new HashSet<UserDetails>();
}
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Equipment> Equipment { get; set; }
public virtual ICollection<UserDetails> UserDetails { get; set; }
}
try decorating one of the navigation properties with [IgnoreDataMember]
[IgnoreDataMember]
public virtual ICollection<Equipment> Equipment { get; set; }
The model generated by upshot can be found on the page itself. In your Index view you will see the UpshotContext HTML helper being used (given that you are using the latest SPA version), in which the dataSource and model type are specified.
When the page is then rendered in the browser, this helper code is replaced with the actual model definition. To see that, view the source code of your page in the browser and search for a <script> tag that starts with upshot.dataSources = upshot.dataSources || {};
Check here for more info about how upshot generates the client side model.
As for the "backtracking of references", I don't know :)
I figured out - partially how to solve the circular reference problem.
I just iterated over my queried collection (with Include() ) and set the backreferences to the parent to NULL. That worked for the serialisation issue which otherwise already breaks on the server.
The only problem now is the update of a data entity - its failing because the arrays of the referenced entitycollection are static...
To solve the cyclic backreference, you can use the IgnoreDataMember attribute. Or you can set the back reference to NULL before returning the data from the DbDataController
I posted a working solution to your problem in a different question, but using Entity Framework Code First.
https://stackoverflow.com/a/10010695/1226140
Here I show how to generate your client-side model manually, allowing to you to map the data however you please