In ASP.NET I'm using Entity Framework with a code-first approach and I want based on my model to generate the DB table. One of the attributes is Enum value, and it is not showing as a column in the generated table.
So this is my enum:
public enum MyEnum
{
val_one = 1,
val_two = 2,
val_three = 3
}
And this is my model:
public class MyModel
{
public int Id { get; set; }
public string attrString { get; set; }
public double attrDouble { get; set; }
public MyEnum attrEnum { get; set; }
}
So with the code-first approach I'm having generated table with the following columns:
CREATE TABLE [dbo].[MyModel]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[attrString] NVARCHAR (MAX) NOT NULL,
[attrDouble] FLOAT (53) NOT NULL,
[attrEnum] INT NOT NULL,
CONSTRAINT [PK_dbo.MyModel] PRIMARY KEY CLUSTERED ([Id] ASC)
);
And later when generating forms (controller and views) based on the model, I'm having a forms where attrEnum param is missing.
So how to proceed in order to have this enum attribute (in format of dropdown list) in the forms (still using code-first approach). I guess there may be needed generation of another DB table that will contains enums, but I'm really not sure how to do that in Entity Framework since I'm beginner in it.
You could take an easier approach...
In the controller, for example:
public ActionResult Edit(int? id)
{
List<SelectListItem> myOptions = new List<SelectListItem>();
myOptions.Add(new SelectListItem() { Text="1", Value = "1" });
myOptions.Add(new SelectListItem() { Text = "2", Value = "2" });
myOptions.Add(new SelectListItem() { Text = "3", Value = "3" });
ViewData["OptionList"] = new SelectList(myOptions, "Value", "Text");
Then in the Edit.cshtml:
#Html.DropDownListFor(model => model.Status, (SelectList)ViewData["OptionList"], new { #class = "form-control dropdown" })
You get a nice styled dropdown with options you're looking for.
Related
I create a #Html.DropDownListFor and populate it from the database. How can I set a selected value to the drop down?
My View:
#Html.DropDownListFor(m => m.Forms, new SelectList(Model.Forms, "FormsCreatorID", "FormName"),
"Select a Form", new { #class = "form-control" })
My Controller:
var forms = db.formscreators.Where(fp => fp.PropertyID == id || fp.PropertyID == 0)
.OrderByDescending(x => x.PropertyID).GroupBy(x => x.FormName).Select(x => x.FirstOrDefault()).ToList();
var viewModel = new ListFormsCreator { Forms = forms };
My ViewModel:
public class ListFormsCreator
{
public List<formscreator> Forms { get; set; }
}
My Database Model:
public partial class formscreator
{
public int FormsCreatorID { get; set; }
public string FormName { get; set; }
public int PropertyID { get; set; }
}
Thanks
You should add another property to your view model for the store/pass the selected option.
public class ListFormsCreator
{
public int SelectedFormId { set;get;}
public List<formscreator> Forms { get; set; }
}
Now in your GET action, you can set that value
var viewModel = new ListFormsCreator() { Forms = forms };
viewModel.SelectedFormId = 2 ; // This will select the option with 2 as FormsCreatorID
return View(viewModel);
And in the view use the lambda expression with that property as the first parameter of the DropDownListFor helper method.
#model ListFormsCreator
#Html.DropDownListFor(m => m.SelectedFormId ,
new SelectList(Model.Forms, "FormsCreatorID", "FormName"),
"Select a Form", new { #class = "form-control" })
The DropDownListFor helper method will use the value of SelectedFormId property and select the option which has the same value attribute value from the list of options of that SELECT element.
You can also remove the dependency on formscreator class from the view model, by replacing it with a list of SelectListItem
public class ListFormsCreator
{
public int SelectedFormId { set;get;}
public List<SelectListItem> Forms { get; set; }
}
Now in your GET action, you can use the Select method to generate the lsit of SelectListItem from your other collection.
var viewModel = new ListFormsCreator();
viewModel.Forms = someCollection.Select(a=>new SelectListItem {
Value=a.FormsCreatorId.ToString(),
Text=a.FormName})
.ToList();
viewModel.SelectedFormId = 2 ; // This will select the option with 2 as FormsCreatorID
return View(viewModel);
Assuming someCollection is a collection of formscreator objects
Now in the view code is much simpler
#Html.DropDownListFor(m => m.SelectedFormId, Model.Forms ,"Select a Form")
Conform with C#/.NET naming conventions:
Rename formscreator to FormsCreator
Replace ID with Id (as it's an abbreviation, not an initialism)
Rename ListFormsCreator to something like ListFormsCreatorViewModel so it's obvious it's a ViewModel type and not a Model/Entity type.
Modify your ViewModel to add a property to store the selected FormsCreatorId value:
public class ListFormsCreatorViewModel
{
[Required] // add or remove the 'Required' attribute as necessary
public int? SelectedFormsCreatorId { get; set; }
...
}
Set the SelectedFormsCreatorId property value in your controller action if necessary if you know what the value should be.
In your POST handler, ensure the SelectedFormsCreatorId value is maintained, either by directly passing-through the model action parameter back through the View(Object viewModel) method or manually repopulating it.
The view-model property in DropDownListFor should be the SelectedFormsCreatorId property. You do not need new SelectList(...)
#Html.DropDownListFor( m => m.SelectedFormsCreatorId, this.Model.Forms );
Update your viewModel and add an Int SelectId for the dropdown selected value.
In your controller:
var viewModel = new ListFormsCreator { SelectId = PropertyId, Forms = FormSelectList(forms, PropertyId.ToString()) };
I would create a function passing in a list:
public static SelectList FormSelectList(IEnumerable<formscreators> types, string selected = null)
{
return new SelectList(from f in forms
select new SelectListItem
{
Text = f.FormName,
Value = f.FormsCreatorID.ToString()
}, "Value", "Text", selected);
}
And in your .cshtml
#Html.DropDownListFor(m => m.PropertyId, Model.forms, "Select a Form", new { #class = "form-control", required = "required" })
You should generate a 'SelectListItem' list on the controller with setting 'Selected' value and pass it via ViewBag or ViewModel. In my sample, for simplicity, I used ViewBag.
Here is the shortened Controller:
public ActionResult Edit(int? id)
{
if (id == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
Album album = context.Albums.Find(id);
if (album == null)
{
return HttpNotFound();
}
ViewBag.GenreId = context.Genres.Select(
g => new SelectListItem()
{
Value = g.GenreId.ToString(),
Text = g.Name,
Selected = g.GenreId == album.GenreId ? true : false
}).ToList();
return View(album);
}
Here is the shortened View Code
#using MvcMusicStore2017.Models;
#model Album
#Html.DropDownList("GenreId", null, new { #class = "form-control" })
I am attempting to save user preferences into a table but am getting a null exception and I do not understand why. This is an MVC 4 application and this is my action result where I am getting the error.
public ActionResult Go(string path, string name)
{
RaterContext r = new RaterContext();
UserData u = new UserData();
var userid = u.GetCurrentUserData().UserId;
var info = r.RatersInfo.Where(w => w.RaterName.Equals(name)).FirstOrDefault();
var pref = r.RatersPreferences.Where(w => w.RaterId.Equals(info.RaterId) && w.UserId.Equals(userid)).FirstOrDefault();
if (pref != null && pref.Count > 0)
{
pref.Count++;
r.SaveChanges();
}
else
{
pref = new RaterPreferences();
pref.UserId = userid;
pref.RaterId = info.RaterId;
pref.Count = 1;
r.RatersPreferences.Add(pref);
r.SaveChanges();
}
return Redirect(path);
}
There is nothing saved in the preferences table yet so it is hitting the else block and throwing a null exception on r.SaveChanges();. The exception is
Cannot insert the value NULL into column 'UserId', table
'WebSiteNew.dbo.RaterPreferences'; column does not allow nulls. INSERT
fails.\r\nThe statement has been terminated.
The reason this doesn't make sense is because all three properties, including the UserId have data when I step through. These are the only fields in the table. UserId = 1, RaterId = 6 and Count is clearly set to 1. They are all set as non-nullable ints and the primary key is a combination of UserId and RaterId. My Model is as follows.
public class RaterContext : DbContext
{
public RaterContext()
: base("DefaultConnection")
{
}
public DbSet<RaterInfo> RatersInfo { get; set; }
public DbSet<RaterPreferences> RatersPreferences { get; set; }
}
[Table("RaterInfo")]
public class RaterInfo
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int RaterId { get; set; }
public string RaterName { get; set; }
public string RaterLink { get; set; }
public string Section { get; set; }
public string Department { get; set; }
}
[Table("RaterPreferences")]
public class RaterPreferences
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public int RaterId { get; set; }
public int Count { get; set; }
}
Any help would be greatly appreciated as I am relatively new to MVC and ASP.NET. Let me know if you need more information. Thanks in advance!
I don't know if this helps but I tested to see what would happen on UPDATE by adding data manually so it would catch on the if block and that works. I'm only getting an error on INSERT.
Here is the create statement for the table in question.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[RaterPreferences](
[UserId] [int] NOT NULL,
[RaterId] [int] NOT NULL,
[Count] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
[UserId] ASC,
[RaterId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[RaterPreferences] WITH CHECK ADD CONSTRAINT [FK_RaterPreferences_RaterInfo] FOREIGN KEY([RaterId])
REFERENCES [dbo].[RaterInfo] ([RaterId])
GO
ALTER TABLE [dbo].[RaterPreferences] CHECK CONSTRAINT [FK_RaterPreferences_RaterInfo]
GO
I have copied your code into a brand new ASP.Net MVC project with the current version of Entity Framework and I am able to run your code with no problems. I escaped the UserData acquisition with code that looks like:
RaterContext r = new RaterContext();
//UserData u = new UserData();
var userid = 1; // u.GetCurrentUserData().UserId;
var info = r.RatersInfo.Where(w => w.RaterName.Equals(name)).FirstOrDefault();
and did not have a problem running the remainder of this code.
I think you may have some problems with your keys and database structure for the RaterPreferences table. I don't know your full data-model, but I don't understand how this fits in, and it is not keyed in your code the way that you describe.
Edit:
I've modified my database tables to reflect the design you've described. You have a difference between your EntityFramework code-first implementation and your database. It looks like your database existed first, and I would remove your EntityFramework classes and rebuild them with Database First techniques.
I would like to use the following code by extending the #Html.DropDownListFor helper.
My controller gets a list, and I am adding a default value to the IEnumerable in my view model. However I don't want to write all of this every time I want a dropdown with a default value. So extending the helper seems logical.
public class SiteGetSitesViewModel
{
public string SelectedSiteId { get; set; }
public IEnumerable<SelectListItem> SiteListItems { get; set; }
}
public ActionResult GetSites()
{
List<SiteDto> sites = _siteService.GetSites();
const string defaultText = "Select a site";
const string defaultValue = "-1";
var siteGetSitesViewModel = new SiteGetSitesViewModel
{
SiteListItems = Enumerable.Repeat(new SelectListItem
{
Selected = true,
Text = defaultText,
Value = defaultValue
}, 1).Concat(sites.Select(s => new SelectListItem
{
Text = s.SiteName,
Value = s.SiteId.ToString()
}))
};
return PartialView("_GetSites", siteGetSitesViewModel);
}
Html.DropDownListFor supports adding a default value to the choices already, so there is no need to reinvent the wheel:
Use this overload:
http://msdn.microsoft.com/en-us/library/ee703567(v=vs.108).aspx
#Html.DropDownListFor(
m => m.Property,
GetSelectList(),
"defaultOption", // the text for the default option goes here
null
)
If I had a class defined with this attributes
public class GestionesDataSet
{
public DateTime GestionInicio { get; set; }
public DateTime GestionFin { get; set; }
public Nullable<DateTime> LlamadaInicio { get; set; }
public Nullable<DateTime> LlamadaFin { get; set; }
public string Login { get; set; }
public string Tipificacion { get; set; }
public List<CamposGestion> campoValor { get; set; }
}
And the class called CamposGestion is defined like this
public class CamposGestion
{
public string Nombre { get; set; }
public string Valor { get; set; }
}
How can I Defined a report where I can use the field that refers to the list of the other elements?
I tried to used one dataset where I can set this linq as object data source
var gestiones = (from G in db.Gestion
where
G.IDTipificacion == idTipificacion
&& (from T in db.Tipificacion where T.IdTipificacion == G.IDTipificacion select T.Servicio.IDServicio).AsEnumerable().Contains(idServicio)
select G).AsEnumerable().Select(xx => new GestionesDataSet()
{
GestionInicio = xx.HoraInicio,
GestionFin = xx.HoraFin,
#Tipificacion = ((from T in db.Tipificacion select T).Where(x => x.IdTipificacion == xx.IDTipificacion).Count() > 0 ?
(from T in db.Tipificacion where T.IdTipificacion == xx.IDTipificacion select T.Nombre).FirstOrDefault() : ""),
LlamadaInicio = xx.Llamada.HoraInicio,
LlamadaFin = xx.Llamada.HoraFin,
Login = xx.Llamada.Sesion.Usuario.Nombre,
campoValor = xx.CampoValor.Select(aux => new CamposGestion() {
Nombre = aux.ConfiguracionCampo.Campo.Nombre,
Valor = aux.Valor
}).ToList()
}).ToList();
But what I want to see the report the field that contains the List show's an error like this
Any help would be appreciate.
I would rewrite the query like this:
var gestiones =
from xx in db.Gestion
where
xx.IDTipificacion == idTipificacion
&& (from T in db.Tipificacion
where T.IdTipificacion == xx.IDTipificacion select T.Servicio.IDServicio).AsEnumerable().Contains(idServicio)
select new GestionesDataSet()
{
GestionInicio = xx.HoraInicio,
GestionFin = xx.HoraFin,
#Tipificacion = (from T in db.Tipificacion where T.IdTipificacion == xx.IDTipificacion select T.Nombre).FirstOrDefault() ?? "",
LlamadaInicio = xx.Llamada.HoraInicio,
LlamadaFin = xx.Llamada.HoraFin,
Login = xx.Llamada.Sesion.Usuario.Nombre,
campoValor = xx.CampoValor.Select(aux => new CamposGestion()
{
Nombre = aux.ConfiguracionCampo.Campo.Nombre,
Valor = aux.Valor
}).ToList()
}).ToList();
When you call a projection (Select) after the AsEnumerable was called, LINQ will try to get the navigation objects first from the already loaded ones. If no object is loaded, then will execute a select SQL command for each navigation property used in the projection. If the [DeferredLoadingEnabled][1] property is set to false it won't execute any query and if no object is loaded already (they can be loaded "apriori" with [LoadWith][2]) it will give a NullReferenceException. So, in some situations, calling AsEnumerable might hurt performance. All these things are not valid when AsEnumerable is used in the where parts.
For giving a default value, when no Tipificacion doesn't exist, it can be used the null-coalescing operator, from C#, instead of using the Count method, which creates an extra lookup on the the table.
Now.. to your problem.
SSRS doesn't support binding to a list of items. The column campoValor tries to bind to a list of objects, which is not allowed. So either you create a subreport (there is a section which describes this) or you flatten your data (having the all the properties on one single object) and then use the HideDuplicates property
I need simple DropDownList in form and I don't want to create something like ViewModel.
I have two models(tables) in relation 1:n:
public class Course
{
public int ID { get; set; }
public string Name { get; set; }
}
and
public class Project
{
public int ID { get; set; }
public int CourseId { get; set; }
public int ProjectNo { get; set; }
public string Name { get; set; }
public DateTime Deadline { get; set; }
}
In the 'Create Project' I want to have DropDownList with Id (as value) and Name(as text) from Course table(model). In the new project will be insert chosen CourseId. How can I do that as simple as possible?
Any particular reason why you don't want to use a ViewModel? They're very helpful for this type of problem.
If you don't want to use a ViewModel, then you can construct a specific class in your controller that is an aggregate of the properties you need from both classes:
public ActionResult Show(int id)
{
Course course = repository.GetCourse(id); // whatever your persistence logic is here
Project project = projectRepository.GetProjectByCourseId(id);
string CourseName = from c in course where
c.ID == project.courseID
select c.Name;
IEnumerable<SelectListItem> selectList =
from c in course
select new SelectListItem
{
Selected = (c.ID == project.CourseId),
Text = c.Name,
Value = project.CourseId.ToString()
};
//add the selectList to your model here.
return View(); //add the model to your view and return it.
}
It would be far easier to have a ViewModel for this, so you could have a strongly typed view. Let me show you:
public class ProjectCourseViewModel
{
public SelectList ProjectCourseList {get; private set; }
public Project Project {get; private set; }
public Course Course {get; private set; }
public ProjectCourseViewModel(Project project, Course course)
{
ProjectCourseList = GetProjectCourseSelectList(project, course)
Project = project;
Course = course;
}
private SelectList GetProjectCourseSelectList(Project project, Course course)
{
IEnumerable<SelectListItem> selectList =
from c in course
select new SelectListItem
{
Selected = (c.ID == project.CourseId),
Text = c.Name,
Value = project.CourseId.ToString()
};
}
}
And then your controller would be really simple:
public ActionResult Show(int id)
{
Course course = repository.GetCourse(id);
Project project = projectRepository.GetProjectByCourseId(id);
ProjectCourseViewModel pcvm = new ProjectCourseViewModel(project, course)
return View(pcvm);
}
And then your view takes in a strongly typed model, and you don't have to rely on ViewData, which is a Good Thing.
Note: I haven't compiled this, just written it. There are probably compilation bugs.
probably you could solve it using the following example:
in your controller include a Viewbag
{
Viewbag.Course = db.course.ToList();
var project = new project.....
}
And in your View use the following pattern:
#Html.DropDownList("CourseId",
new SelectList(ViewBag.Course as System.Collections.IEnumerable,
"CourseId", "Name", Model.ID))
where each field represent:
•The name of the form field (CourseId)
•The list of values for the dropdown, passed as a SelectList
•The Data Value field which should be posted back with the form
•The Data Text field which should be displayed in the dropdown list
•The Selected Value which is used to set the dropdown list value when the form is displayed
more info at: http://www.asp.net/mvc/tutorials/mvc-music-store-part-5
brgds.
In the Controler:
var CourseName = from c in course where
c.ID == project.courseID
select c.Name;
SelectList sl = new SelectList(CourseName);
ViewBag.names= sl;
in the view :
#Html.DropDownList("Name", (SelectList)ViewBag.names)