I have the following controller in an ASP.Net WebApi project.
The model is generated with Entity Framework.
public class CategoriesController : ApiController
{
private eLearningDbEntities context = new eLearningDbEntities();
// GET api/Categories
public IEnumerable<Categories> GetCategories()
{
var query = from c in context.Categories
select c;
return query;
}
}
When call the controller from the browser I get the following result, but I want to get only the properties of the Model, not all the context properties. Any ideas what is wrong?
<ArrayOfCategories xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/eLearning.DomainModel">
<Categories xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<EntityKey xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Data" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" z:Id="i2">
<d3p1:EntityContainerName>eLearningDbEntities</d3p1:EntityContainerName>
<d3p1:EntityKeyValues>
<d3p1:EntityKeyMember>
<d3p1:Key>ID</d3p1:Key>
<d3p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:int">1</d3p1:Value>
</d3p1:EntityKeyMember>
</d3p1:EntityKeyValues>
<d3p1:EntitySetName>Categories</d3p1:EntitySetName>
</EntityKey>
<ID>1</ID>
<Name>e-Business</Name>
</Categories>
<Categories xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i3">
<EntityKey xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Data" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" z:Id="i4">
<d3p1:EntityContainerName>eLearningDbEntities</d3p1:EntityContainerName>
<d3p1:EntityKeyValues>
<d3p1:EntityKeyMember>
<d3p1:Key>ID</d3p1:Key>
<d3p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:int">2</d3p1:Value>
</d3p1:EntityKeyMember>
</d3p1:EntityKeyValues>
<d3p1:EntitySetName>Categories</d3p1:EntitySetName>
</EntityKey>
<ID>2</ID>
<Name>SADE</Name>
</Categories>
</ArrayOfCategories>
Thank you!
You shouldn't be passing back your database entity directly, but instead creating a view model that you can pass back that isolates the message to only the fields that you care about receiving on the client end. e.g.
// Create a View Model to hold appropriate properties
public class MyViewModel
{
public string PropertyA {get; set;}
public string PropertyB {get; set;}
}
...
// Map your entity to the View Model and return it.
var viewModel = context.Categories.Select(
e=>new MyViewModel(){
PropertyA = e.SomeProperty,
PropertyB = e.AnotherProperty
});
return viewModel;
Related
I want to pass the data from controller to my modal class.
Here is a test example of what I want to do,
I can't publish my code here as my code is very large in number of lines.
[HttpPost]
public ActionResult testdata()
{
string testdata = "send test data";//this data i want to pass to my model class
return View();
}
as my modal class is inserting the same data into database
public bool inserttestdata()
{
cmd = new SqlCommand();
cmd.Parameters.AddWithValue("#test", "test data want here");//here I want to use the data which i declared in my controller
int i = dbf.ExecuteSP("testproc", cmd);
if (i >= 1)
return true;
else
return false;
}
This is just a test data, my actual code is very large and the data which I want to insert is dynamic and not static.
Where are you calling inserttestdata() from? You need to pass the testdata as a parameter to this method.
Here for example : public bool inserttestdata(string testdata)
then call inserttestdata(testdata)
You can store data to model simply like this-
MyModel model = new MyModel();
model.someVariable = "your data";
Where your model would look like-
public class MyModel
{
public string someVariable {get; set;}
}
C# Web.Api Odata APplication
I’m implementing Odata V4 for the first time and would like to use my own custom class instead of the data class from the designer.
Here is what I did:
I created a Data project in Visual Studios and added my SQL Linq data table “Video”
I created the data context as follows:
public class VideoDataContext : DbContext
{
public VideoDataContext(): base("name=VideoData")
{
DbSet<VideoEf> Videos { get; set; }
}
And my custom class as follows:
[Serializable]
[DataContract]
public class VideoEf : Repository
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Isrc { get; set; }
}
And model builder:
public Microsoft.OData.Edm.IEdmModel GetEdmModel()
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
EntityTypeConfiguration<VideoEf> titleType = builder.EntityType<VideoEf>();
builder.EntitySet<VideoEf>("Video");
return builder.GetEdmModel();
}
And in my video controller:
public class VideoController : ODataController
{
VideoDataContext db = new VideoDataContext ();
[EnableQuery(PageSize = 20, MaxExpansionDepth = 5)]
public IHttpActionResult Get()
{
return Ok(db.Videos.AsQueryable());
}
When I make the call to get the video entities I keep getting a ” 406 Not Acceptable” error message
How can I ensure that the data returned from the database is mapped to my custom model ?
Is my model builder correct?
what could be causing the above error?
You don't need to return IQueryable because you have EnableQuery attribute, just return DbSet.
You also don't need any wcf attribute and EntityTypeConfiguration<VideoEf> titleType = builder.EntityType<VideoEf>();
Then it should just work.
Hope it helps.
Edit
My mistake for IQueryable, I also use it.
I can't seem to get the edit function of my view to work..i have a page that lists, a page that shows specific detail and on that page, i should be able to edit the information of the form..PROBLEM: when i run the application it says:No parameterless constructor defined for this object. What am i doing wrong...?
In the Home Controller i have:
Edit Functions:
[HttpGet]
public ViewResult EditSchoolDetails(int id)
{
var institution = _educationRepository.GetInstititionById(id);
var model = (Mapper.Map<Institution, InstitutionModel>(institution));
return View(model);
}
post
[HttpPost]
public ActionResult EditSchoolDetails( InstitutionModel institutionModel, int id)
{
if (ModelState.IsValid) {
//_get from repository and add to instituion
var institution = _educationRepository.GetInstititionById(institutionModel.Id);
// Map from the view model back to the domain model
var model = Mapper.Map<Institution, InstitutionModel>(institution);
//UpdateModel(model);
SaveChanges();
return RedirectToAction("ViewSchoolDetails", new {institutionModel = institutionModel, id = id});
}
return View(institutionModel);
}
InstitutionModel
public class InstitutionModel {
public InstitutionModel() {
NAABAccreditations = new List<AccreditationModel>();
}
public int Id { get; set; }
public string Name { get; set; }
public bool IsNAAB { get { return NAABAccreditations.Any(); } }
public string Website { get; set; }
public AddressModel Address { get; set; }
public IEnumerable<AccreditationModel> NAABAccreditations { get; set; }
}
Does the Institution class have a parameterless constructor? If not, that will be the problem. You are passing an InstitutionModel to the the edit view, so the post action should probably take an InstitutionModel too, then you can map back to the original Institution model:
public ActionResult EditSchoolDetails(int id, InstitutionModel institutionModel)
{
if (ModelState.IsValid)
{
//add to database and save changes
Institution institutionEntity = _educationRepository.GetInstititionById(institution.Id);
// Map from the view model back to the domain model
Mapper.Map<InstitutionModel, Institution>(institutionModel, institutionEntity);
SaveChanges();
return RedirectToAction("ViewSchoolDetails",);
}
return View(institutionModel);
}
Notice also how it returns the view model back to the view if the model state isn't valid, otherwise you will lose all your form values!
Here's a similar question too which might help: ASP.NET MVC: No parameterless constructor defined for this object
Is it possible you need to pass a parameter to ViewSchoolDetails? I notice in the return statement you commented out that you were passing it an id, but in the return statement you're using, you're not passing in anything.
EDIT
This (from your comment below):
parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult ViewSchoolDetails(Int32)
...tells me you need to pass a parameter to ViewSchoolDetails
EDIT 2
I saw your edit, and would say this: if the method you are calling is
public ActionResult ViewSchoolDetails(InstitutionModel institutionModel, int id)
Then you MUST pass it an object of type InstitutionModel and an int as parameters or you will get an exception. Meaning, you need
RedirectToAction("ViewSchoolDetails", new {institutionModel = institutionModel, id = id});
Whenever i get this, i have forgotten to create a parameter-less constructor on my view-model. I always add one now just in case it's needed and i forget.
Does InstitutionModel have one?
can anybody provide a link for creating a viewmodel for the edmx designer class
suppose my edmx file is named School.edmx and it has school.Designer.cs class.
In the designer class i have the folowing entity object
[EdmEntityTypeAttribute(NamespaceName="teamworkModel", Name="User")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class User : EntityObject
{
#region Primitive Properties
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 User_Pk
{
get
{
return _User_Pk;
}
set
{
if (_User_Pk != value)
{
OnUser_PkChanging(value);
ReportPropertyChanging("User_Pk");
_User_Pk = StructuralObject.SetValidValue(value);
ReportPropertyChanged("User_Pk");
OnUser_PkChanged();
}
}
}
private global::System.Int32 _User_Pk;
partial void OnUser_PkChanging(global::System.Int32 value);
partial void OnUser_PkChanged();
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
[Required(ErrorMessage="Please enter your name")]
[StringLength(20,ErrorMessage="Name cannot exceed 20 characters")]
[RegularExpression(#"^([a-zA-Z0-9 \.\&\'\-]+)$", ErrorMessage = "Invalid name")]
public global::System.String User_Name
{
get
{
return _User_Name;
}
set
{
OnUser_NameChanging(value);
ReportPropertyChanging("User_Name");
_User_Name = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("User_Name");
OnUser_NameChanged();
}
}
private global::System.String _User_Name;
partial void OnUser_NameChanging(global::System.String value);
partial void OnUser_NameChanged();
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
[Email(ErrorMessage="Invalid email address")]
[Required(ErrorMessage="Please enter email address")]
public global::System.String User_Mail_Id
{
get
{
return _User_Mail_Id;
}
set
{
OnUser_Mail_IdChanging(value);
ReportPropertyChanging("User_Mail_Id");
_User_Mail_Id = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("User_Mail_Id");
OnUser_Mail_IdChanged();
}
}
private global::System.String _User_Mail_Id;
partial void OnUser_Mail_IdChanging(global::System.String value);
partial void OnUser_Mail_IdChanged();
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
[Required(ErrorMessage="Please enter password")]
[StringLength(20,ErrorMessage="Password cannot exceed 20 characters")]
[RegularExpression(#"^([a-zA-Z0-9 \.\&\'\-]+)$", ErrorMessage = "Invalid password")]
public global::System.String User_Password
{
get
{
return _User_Password;
}
set
{
OnUser_PasswordChanging(value);
ReportPropertyChanging("User_Password");
_User_Password = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("User_Password");
OnUser_PasswordChanged();
}
}
private global::System.String _User_Password;
partial void OnUser_PasswordChanging(global::System.String value);
partial void OnUser_PasswordChanged();
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime User_Creation_Date
{
get
{
return _User_Creation_Date;
}
set
{
OnUser_Creation_DateChanging(value);
ReportPropertyChanging("User_Creation_Date");
_User_Creation_Date = StructuralObject.SetValidValue(value);
ReportPropertyChanged("User_Creation_Date");
OnUser_Creation_DateChanged();
}
}
private global::System.DateTime _User_Creation_Date;
partial void OnUser_Creation_DateChanging(global::System.DateTime value);
partial void OnUser_Creation_DateChanged();
I have the following columns in the above entity object (User table)User_PK,User_Name,User_Password,User_Email_ID.....
Please can anyone suggest how to create a viewmodel for the above entity object that contains all the above columns except User_Password and User_Email_ID because i need to use it as strongly typed viewmodel for my view.I also need to use another table in the same viewmodel with selected columns....
i had gone through a lot of documents..i already spent 1 and half day for this
can anybody help..
i know this question is asked repeatedly but i cannt find the right way in doing it...
Thanks
Edit: Modified to answer comment about extra properties from other Entities
This may help
public class UserViewModel
{
public int Pk{get;private set;}
public string Name{get;set;}
public DateTime CreationDate{get;set;}
public string ProjectName{get;set;}
public DateTime ProjectCreated{get;set;}
}
The ViewModel is a flattened version of you entities.
You have to write your viewmodel classes yourself.
Just create a class called something like MyWebApp.Models.User which contains the properties you need and map the edmx class to it in your controller.
For mapping i recommend using the automapper which makes mapping life easier.
EDIT
This is how you use automapper:
Say your DAL class is called User and your viewmodel class is called UserViewModel.
You have to tell automapper once which classes you want to map:
AutoMapper.Mapper.CreateMap<User, UserViewModel>();
Then you can map objects from one type to another with a single line:
User user = dal.GetUser();
UserViewModel model = AutoMapper.Mapper.Map<User, UserViewModel>(user);
Automapper can even map collections of objects. So if your model has a property like IEnumerable<Projects> it will map this as well.
I get VS to do most of the work for me by right clicking on the edmx design surface and selecting Add Code Generation Item > EF 5.x DBContext Generator > Add.
You should then see a [xxx].tt file in the same folder as your edmx file. If you expand this file you should see a POCO class for each of your entities.
I copy the entities as required into my viewmodel and delete the ones I don't need.
Once I'm happy with my viewmodel I delete the [xx].tt file, right click properties on the edmx design surface > Properties > Code Generation strategy > default.
I'd also highly recommend using Automapper as Jan mentioned in his answer.
In my controller I have the following code:
var viewModel = new ListCityViewModel {
City = rowData,
Meta =
{
DataSourceID = dataSourceID,
Em0 = em0
}
};
In my viewModel I have the following:
public class ListCityViewModel : BaseViewModel
{
public ListCitiesViewModel()
{
Meta = new Meta
{
Title = ViewContext.Controller.ValueProvider.GetValue("controller").RawValue +
ViewContext.Controller.ValueProvider.GetValue("action").RawValue,
Desc = ViewContext.Controller.ValueProvider.GetValue("controller").RawValue +
ViewContext.Controller.ValueProvider.GetValue("action").RawValue
};
}
public ICollection<City> Cities { get; set; }
}
and:
public class BaseViewModel
{
public BaseViewModel()
{
}
public Meta Meta { get; set; }
}
However it's not working as I get a message:
Error 6 An object reference is required for the non-static field,
method, or property 'System.Web.Mvc.ControllerContext.Controller.get'
Can anyone help me with this one. Do I need to pass something to the viewModel from the controller and how can I pass it. I have this viewModel common to many actions so I would like this to be automatic rather than me having to specify in the controller the controller name and action name.
In short : do not do that. It is not the right thing to do in MVC pattern. Your viewmodels should be as dumb as possible, and without any "contexts". If you need some "meta" data in your view models, depending for example on route data (action, controller), write a custom filter, which will put it there in OnActionExecuted - for example look by reflection if the current viewmodel has your "meta" properties (by this you make your own convention) and fill them from route data.