I have a service layer that exposes a method, which returns me a List, called GetStates.
public List<StateObject> GetStates()
My State Object is just a custom object I have created:
public class StateObject
{
public int stateId { get; set; }
public string description { get; set; }
public Boolean isDefault { get; set; }
}
In my models, I am trying to create a model that will be used for my display and modification screen of a task. One thing this will be used for is handling the display and selection of a Drop down box, which will give a list of States available for my Task. So, my model looks something like this (Removed properties we don't car about - it's a bit bigger than this:
public class TaskModifyModel
{
public int stateId { get; set; }
public string state { get; set; }
public SelectList states { get; private set; }
public TaskModifyModel()
{
states = new SelectList(
(new ReferenceService().GetStates()),
"stateId",
"description",
1);
}
}
So, stateId holds the selected state, state holds the text description of the selected state. In the constructor, I am attempting to create a states SelectList for the view... and populate it.
In the view, I then try to display the Drop Down List:
#Html.DropDownListFor(m=>m.stateId, new SelectList(Model.states, "stateId", "description", Model.priorityId))
This is failing, dismally.
DataBinding: 'System.Web.Mvc.SelectListItem' does not contain a property with the name 'stateId'.
I have searched, and I thought I was doing this the right way, but the error says I am not.. clearly. :) Could someone guide me on why it's not working, and also, is this the right way to do things?
Edit:
After assistance below, it's now working. If I am creating a new task (taskId==0), then I have to get the default value of the dropdown, as stored in my database.... So, is this clean? This is my working constructor for the object:
public TaskModifyModel()
{
var referenceService = new ReferenceService();
var p = referenceService.GetPriorities();
var s = referenceService.GetStates();
var defaultP = (from a in p where a.isDefault select a).FirstOrDefault();
var defaultS = (from a in s where a.isDefault select a).FirstOrDefault();
priorities = new SelectList(
(p),
"priorityId",
"description"
);
priorityId = taskId == 0 ? defaultP.priorityId : priorityId;
states = new SelectList(
s,
"stateId",
"description");
stateId = taskId == 0 ? defaultS.stateId : stateId;
}
Is it OK?
Your public SelectList states { get; private set; } is already a SelectList so you don't need to cast it again in your View.
Try this instead:
#Html.DropDownListFor(m=>m.stateId, Model.states)
And in your ViewModel, remove the parameter "SelectedValue". The #Html.DropDownListFor will initialize the dropdown to the right value.
public class TaskModifyModel
{
public int stateId { get; set; }
public string state { get; set; }
public SelectList states { get; private set; }
public TaskModifyModel()
{
states = new SelectList(
(new ReferenceService().GetStates()),
"stateId",
"description");
}
}
Related
I'm going for the edit data by ProuctId.i have 2 table like Product and productitems.so i m click on edit go for the id by getting data but that time i m fetch data by id in the product table is getting propare but after going for the list productitems data getting like this error.
this is my class ProductItmes:
[Table("ProductItems ")]
public class ProductItems
{
[Key]
public int id { get; set; }
[ForeignKey("Products")]
public int pid {get; set;}
public int Qty { get; set; }
public Decimal Rate { get; set; }
public virtual Products Products { get; set; }
}
this is my api method:
public ActionResult GetProductByid(int id)
{
var Pro = db.Product.Find(id);
var ProItemList = db.Promotion_ctc.Where(x => x.pid == Pro.id).ToList();//here i am getting list of items by productid
var Details = new
{
Pro.id,
Pro.name,
Pro.image_url,
ProItemList
};
return Json(new { data = Details });
}
idk where is my problem any one know please let me know.
When working with MVC and Entity Framework, there are cases where we make our child entities reference the parent, like you did, by declaring this property here:
public virtual Products Products { get; set; }
it's ok for entity framework, but it's not when you try to serialize this.
What's going on:
The serializer will try to serialize the parent, which has a collection of ProductItem.
The serializer tries to serialize each child.
The child has a reference to parent, so the serializer tries to serialize the parent again.
Infinite loop.
That's why people use ViewModels. Instead of just returning your entities from your action, project them into a view model, and return it. Actually, you're returning an anonymous object containing a ProItemList, which I'd guess it's a List of ProductItems. Just create a view model for it:
public class ProductItemViewModel
{
public int ItemId { get; set; }
public int ProductId {get; set;}
public int Qty { get; set; }
public Decimal Rate { get; set; }
// public virtual Products Products { get; set; } NO PRODUCT HERE
}
...then fix your action to return a List of ProductItemViewModel, instead of returning directly ProductItems, like this:
var ProItemList = db.Promotion_ctc.Where(x => x.pid == Pro.id)
.Select(i => new ProductItemViewModel
{
ItemId = i.ItemId,
ProductId = i.ProductId,
Qty = i.Qty,
Rate = i.Rate
})
.ToList();
var Details = new
{
Pro.id,
Pro.name,
Pro.image_url,
ProItemList
};
return Json(new { data = Details });
}
send only required columns to ui
like this
var passToUi = from s in listResult
select new { s.Id, s.Name };
return Json(passToUi, JsonRequestBehavior.AllowGet);
I have a trouble with reference to my enum from model in Index view.
Here is my model's code:
public enum UnitOfMeasure {
Item,
Kilogram,
Liter, }
public class Product {
public Product() {
ProductOccurences = new List<ProductOccurence>(); }
[Key]
public int ProductId { get; set; }
public int ProductPhotoId { get; set; }
public UnitOfMeasure? UnitOfMeasure { get; set; }
public string ProductDescription { get; set; }
public virtual ProductPhoto Photo { get; set; }
public virtual ICollection<ProductOccurence> ProductOccurences { get; set; } }
In Index view I have search fields for filtering specific results. You can also search for UnitOfMeasure value (I use #Html.EnumDropDownListFor) - but I can't refer directly to the enum field from my model - because my view is strongly typed:
#model IEnumerable<Models.Product>
To show this field with the values of the selection I use the trick:
#Html.EnumDropDownListFor(model => model.FirstOrDefault().UnitOfMeasure, "Select unit of measure")
but it's terrible and ugly solution - also with unwanted value loaded by default.
What is the most elegant way to solve this issue in my situation?
You can use EnumHelper like this:
#Html.DropDownList("UnitOfMeasure", EnumHelper.GetSelectList(typeof(UnitOfMeasure)))
OR
You can do like this for strongly typed view:
#{ // you can put the following in a back-end method and pass through ViewBag
var selectList = Enum.GetValues(typeof(UnitOfMeasure))
.Cast<UnitOfMeasure>()
.Select(e => new SelectListItem
{
Value = ((int)e).ToString(),
Text = e.ToString()
});
}
#Html.DropDownListFor(m => m.UnitOfMeasure, selectList)
I've created an MVC project using entity framework code first. My model is simply a form that gathers information.
public class Application
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public int SSN { get; set; }
public DateTime DOB { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State {get; set; }
public string Zip { get; set; }
public int HomePhone { get; set; }
public int BusinessPhone { get; set; }
public int MobilePhone { get; set; }
}
My goal is to create a drop down list with all of the states, but I'm finding this to be very difficult given that I've already created the database via scaffolding with views and controllers. Is there a simple way to do this and tie it in with the existing database? I've searched for almost the entire day with no luck. An overview/explanation of what to include for the model/controller/view would be amazing!
Update: I've created a new model named "State" with properties "Id" and "StateName" and have created some states in the database. In my "Application" controller inside the Create action method I have:
Controller
public ActionResult Create()
{
ApplicationDbContext db = new ApplicationDbContext();
this.ViewData["Id"] = new SelectList(db.States.ToList(), "Id", "StateName");
return View();
}
View
#Html.DropDownList("Id")
Now the problem is I'm getting this error " There is no ViewData item of type 'IEnumerable' that has the key 'Id'." Would really appreciate help!
Its quite simple. Add an IEnumerable<SelectListItem> property to your model(Here I suggest you make a ViewModel that can have the exact same properties as Application with the below code included as a property). Then you just need to build the list and send it to your view
public IEnumerable<SelectListItem> States{ get; set; }
I will assume you want to retrieve the State values from the db. Here is how you will do it:
private IEnumerable<SelectListItem> GetAllStates()
{
IEnumerable<SelectListItem> list = from s in db.Applications
select new SelectListItem
{
Selected = false,
Text = s.State,
Value = s.State
};
return list;
}
Or this...
private IEnumerable<SelectListItem> GetAllStates()
{
IEnumerable<SelectListItem> list = db.Applications.Select(s => new SelectListItem
{
Selected = false,
Text = s.State,
Value = s.State
});
return list;
}
Then do something like this in your action:
var app = new Application
{
States = GetAllStates()
};
return View(app);
Then finally, use Razor on the view to display the Dropdown list like this
#Html.DropDownListFor(m => m.State, Model.States, "--Select a State--")
The 1st parameter is the property of the model to update, the 2nd is the list of data, and 3rd is the default message that will be displayed
Hope this helps.
Create a data layer that retrieves a list of what you want. Then use EF to get all the states.
//assuming you have a table of states..
var states = db.States();
The states table should be a Unique list of states.
var selectList = new List<SelectListItem>();
foreach(var thing in states){
//if you got everything, thus the ID field for the value...
selectList.Add(new SelectListItem {Text =thing.State, Selected = false, Value = thing.ID);
}
Make sure in your Viewmodel class that selectlist is a public property.....and set to what you did above. You also need to provied a string for the view selection post back.
StatesSelectList = selectList;
public IEnumberable<SelectListItem> StatesSelectList {get;set;}
public string SelectedState {get;set;}
In your view, do this:
#Html.DropDownListFor(p=>Model.SelectedState, Model.StatesSelectList)
Very simple Code step by step
1) In Entity Framework Class
var productsList = (from product in dbContext.Products
select new ProductDTO
{
ProductId = product.ProductId,
ProductName = product.ProductName,
}).ToList();
2) In Controller
ViewBag.productsList = new EntityFrameWorkClass().GetBusinessSubCategoriesListForDD();
3) In View
#Html.DropDownList("Product_ProductId", new SelectList(ViewBag.productsList, "ProductId", "ProductName"), new { #class = "form-control" })
OR
#Html.DropDownListFor(m=>m.Product_ProductId, new SelectList(ViewBag.productsList , "ProductId", "ProductName"), new { #class = "form-control" })
I assume there is a States model that has a Id and a StateName property.
Change to the list to ViewData["State"] to ensure easy binding on POST.
Id is the value that will be sent in the POST data ie.. State = Id. The StateName is what will be displayed in the Select list. So for your model this is not correct as State is a string. So needs to be
this.ViewData["State"] = new SelectList(db.States.ToList(), "StateName", "StateName");
Then in your view
#Html.DropDownList("State")
This is my model:
public class ContentPage
{
public BlogPost BlogPost { get; set; }
public List<BlogPost> BlogPosts { get; set; }
public List<string> Kategorier { get; set; }
}
I would like to use the values in the
public List<string> Kategorier { get; set; }
In a dropdownlistfor, this is what i got so far:
#Html.DropDownListFor(o => o.BlogPost.Kategori, "Here i want my list i guess?"(o => new SelectListItem { Text = o.Kategori, Value = o.Kategori }), "", null)
To clearify, I want to use the values in the List Kategorier in order to set the value for the o.BlogPost.Kategori
Any help appreciated.
There is a number of overloads you can use, but the one I find most readable is
#Html.DropDownListFor(model => model.BlogPost.Kategori,
Model.Kategorier.Select(kat => new SelectListItem { Text = kat, Value = kat })
Part of the reason why I like this overload is just that I prefer strong typing and being helped by the (aspnet) compiler. I generally avoid SelectList and its string-based constructors because they are brittle.
You may want to turn your List<string> into an IEnumerable<SelectListItem> in your view model instead of having to do it in the view.
EDIT:
I would do something like
public class ContentPage
{
public ContentPage(){} //Default constructor needed for model binding
public ContentPage(List<string> kategorier /* and possibly more arguments */)
{
Kategorier = kategorier.Select(k => new SelectListItem { Text = k, Value = k });
}
public BlogPost BlogPost { get; set; }
public List<BlogPost> BlogPosts { get; set; }
public IEnumerable<SelectListItem> Kategorier { get; set; }
}
Be aware that this should be fine for creating new blogposts, but if you want to edit existing blog posts, you will have to do a little more work (categories will have to be selected etc. when you render the page initially etc).
I've built my Domain model layer, my repository layer, and now I'm working on my DTO layer to be used by a webApi project. I'm in the middle of implementing an Update service method, and I'm wondering about partial updates. Here's my DTO class:
public class FullPersonDto
{
public FullPersonDto()
{
Friends = new List<Person>();
}
public FullPersonDto(Person person)
{
PersonId = person.PersonId;
DateCreated = person.DateCreated;
Details = person.Details;
Friends = new List<Person>();
foreach (Person friend in person.Friends)
{
Friends.Add(new PersonDto(friend));
}
}
[Key]
public int PersonId { get; set; }
[Required]
public virtual DateTime DateCreated { get; set; }
public virtual string Details { get; set; }
public List<Person> Friends { get; set; }
public Person ToEntity()
{
var person = new Person
{
PersonId = PersonId,
DateCreated = (DateTime) DateCreated,
Details = Details,
Friends = new List<Person>()
};
foreach (PersonDto friend in Friends)
{
person.Friends.Add(friend.ToEntity());
}
return person;
}
}
Here's my Update method in my Repository:
public Person UpdatePerson(Person person)
{
var entry = _db.Entry(person);
if (entry.State == EntityState.Detached)
{
var dbSet = _db.Set<Person>();
Person attachedPerson = dbSet.Find(person.PersonId);
if (attachedPerson != null)
{
var attachedEntry = _db.Entry(attachedPerson);
attachedEntry.CurrentValues.SetValues(person); // what if values are null, like ID, or DateCreated?
}
else
{
entry.State = EntityState.Modified;
}
}
SaveChanges();
return person;
}
My question is: What if I only need to update the Details of a person via my webAPI? Is the convention to construct an entire PersonDto and Update the entire object using SetValues, or is there any way I can specify that I only want a single field updated so that I don't have to send a ton of data over the wire (that I don't really need)?
If it is possible to do partial updates, when is it ever good to update the entire entity? Even if I have to update 5/7 properties, it requires that I send old data for 2/7 to re-write so that SetValues doesn't write nulls into my fields from my DTO.
Any help here would be awesome... totally new to this stuff and trying to learn everything right. Thank you.
I've taken similar approach to do optimization, and I've faced same issues with null values when attaching (not just null, you'll have issue with boolean as well). This is what I've come up with:
public static void Update<T>(this DbContext context, IDTO dto)
where T : class, IEntity
{
T TEntity = context.Set<T>().Local.FirstOrDefault(x => x.Id == dto.Id);
if (TEntity == null)
{
TEntity = context.Set<T>().Create();
TEntity.Id = dto.Id;
context.Set<T>().Attach(TEntity);
}
context.Entry(TEntity).CurrentValues.SetValues(dto);
var attribute = dto.GetAttribute<EnsureUpdatedAttribute>();
if (attribute != null)
{
foreach (var property in attribute.Properties)
context.Entry(TEntity).Property(property).IsModified = true;
}
}
That is extension method for DbContext. Here are the interfaces IDTO and IEntity:
public interface IDTO
{
int Id { get; set; }
}
public interface IEntity
{
int Id { get; set; }
Nullable<DateTime> Modified { get; set; }
Nullable<DateTime> Created { get; set; }
}
I'm using my custom EnsureUpdatedAttribute to annotate what properties should always be updated (to deal with nulls / default values not being tracked):
public class EnsureUpdatedAttribute : Attribute
{
public IEnumerable<string> Properties { get; private set; }
public EnsureUpdatedAttribute(params string[] properties)
{
Properties = properties.AsEnumerable();
}
}
And this is a sample of usage:
public class Sample : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public Nullable<DateTime> Modified { get; set; }
public Nullable<DateTime> Created { get; set; }
}
[EnsureUpdated("Active")] /// requirement for entity framework change tracking, read about stub entities
public class SampleDTO : IDTO
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[JsonIgnore] /// How to exclude property from going on the wire / ignored for serialization
public bool Active { get; set; }
}
[HttpPost]
public HttpResponseMessage SaveSample(SampleDTO dto)
{
dto.Active = true;
_ctx.AddModel<Sample>(dto);
_ctx.SaveChanges();
return NoContent();
}
return NoContent() is just extension for returning 204 (NoContent).
Hope this helps.
Theres a few options you have, you can create a stored procedure to update the required parts (I wouldnt do this), or you can manually select the fileds to update on the model before saving the context changes with EF.
Heres an example how to update a specific field:
public void UpdatePerson(int personId, string details)
{
var person = new Person() { Id = personId, Details = details };
db.Persons.Attach(personId);
db.Entry(person).Property(x => x.Details).IsModified = true;
db.SaveChanges();
}
It will depend on your scenario what you want to do, but generally speaking its fine to send your whole entity to be updated, and this is how i would approach your situation potentially changing in the future if needed.