Show single data column in ASP.NET MVC 5 using Entity Framework 6 - entity-framework

Sorry if this question have exists.
I using ASP.NET MVC 5 + Entity Framework to build a project and I have a problem which not resolve.
In controller:
private NewsEntities db = new NewsEntities();
public ActionResult Index()
{
var art = db.Articles.Where(m=>m.Id==1).Select(m => new { m.Id , m.NameArt}).ToList();
return View(art);
}
And in view:
#model IEnumerable<DemoHC.Models.Article>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.NameArt)
</td>
<tr>
}
and I when build it in server then display error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType12[System.Int32,System.String]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[DemoHC.Models.Article]'.
Can you help me and thanks pro

Your query is creating a collection of anonymous objects, not a collection of Article objects.
Change your code to
public ActionResult Index()
{
var art = db.Articles.Where(m => m.Id == 1);
return View(art);
}
or alternatively you could create a view model with just the properties you want
public class ArticleVM
{
public int ID { get; set; }
public string Name { get; set; }
}
and change the query to
var art = db.Articles.Where(m => m.Id == 1).Select(m => new ArticleVM
{
ID = m.Id,
Name = m.NameArt
};
return View(art);
and the model in the view will then be
#model IEnumerable<ArticleVM>

Related

Get value of IEnumerable without having to hardcode it

I'm experimenting with adding a Razor page that will display Employees in all stores that belong under the same companies subgroup identifier. If I hard code the value .Contains("ABC") in var employees then I get a list of persons in that company and its subgroups. If I try to use var currentEmpSub, then I do not get my list. I'm not sure what I need to do (add another variable? fix my LINQ query? or something else). Any suggestions would be very helpful! Once I get this I will also do one for a manager view that will show only employees under the managers' store (instead of subgroup).
Setup is a many-to-many relationship with EFCore 5.0
public class Employee
{
public int Id {get; set;}
public string Name {get; set;]
public ICollection<Tenant> Tenants {get; set;}
}
public class Tenant
{
public int Id {get; set;}
public string Name {get; set;]
public ICollection<Employee> Employees{get; set;}
}
Admin.cs
public async Task<IEnumerable<Employee>> GetAllEmployees()
{
var currentEmp = _httpContextAccessor.HttpContext?.User.GetUserId();
var currentEmpTenant = await _context.Employees
.Include(x => x.Tenants)
.Where(e => e.AspUserId == currentEmp)
.FirstAsync();
var currentEmpSub = currentEmpTenant.Tenants
.Select(x => x.SubName)
.ToString();
var employees = _context.Employees
.IgnoreQueryFilters()
.Include(t => t.Tenants)
.Where(x => x.Tenants
.Select(sub => sub.SubName)
.Contains(currentEmpSub))
.ToListAsync();
return await employees;
}
Index.cshtml
#page
#using Navrae.DataLayer.Extensions
#model Navrae.WebApp.Pages.Admin.IndexModel
#{
}
<h2>Employee List</h2>
<table class="table-hover">
<thead>
<tr>
<th>Employee Name</th>
<th>Store</th>
</tr>
</thead>
<tbody>
#foreach (var emp in #Model.Employees)
{
<tr>
<td>#emp.FullName</td>
<td>
#foreach (var comp in emp.Tenants)
{
if (emp.Tenants.Count > 1)
{
String.Join(", ", #comp.CompanyName);
}
else
{
#comp.CompanyName
}
}
</td>
</tr>
}
</tbody>
</table>
Index.cshtml.cs
public class IndexModel : PageModel
{
private readonly IAdminView _adminView;
public IndexModel(IAdminView adminView)
{
_adminView = adminView;
}
public IEnumerable<Employee> Employees { get; set; }
public async Task OnGetAsync()
{
Employees = await _adminView.GetAllEmployees();
}
}
User #Ivan Stoev pointed out that by calling .ToString() produced a List. While it did not solve my problem it was an unintended side effect. I used .SingleOrDefault() on the end of currentEmpSub and obtained the result I was looking for.
**Note you can also use .Single() .First() .FirstOrDefault()
var currentEmpSub = currentEmpTenant.Tenants
.Select(x => x.SubName)
.SingleOrDefault();
``

How to edit nested collections in MVC5?

I have a EF-model which contains a "key" and a "value". The value-table contains a FK to the key. In the EF-model it looks like this:
public partial class dict_key
{
public dict_key()
{
this.dict_value = new HashSet<dict_value>();
}
public int id { get; set; }
public string name { get; set; }
...
public virtual ICollection<dict_value> dict_value { get; set; } //dict_value contains a string "value"
}
My controller is passing the information for editing like this:
// GET: Keys/Texts/5
[Authorize]
public async Task<ActionResult> Texts(int? id)
{
var key = await db.dict_key
.Include(x => x.dict_value)
.Where(x => x.id.Equals(id.Value))
.FirstOrDefaultAsync();
return View(key);
// Debugging 'key' shows that dict_value has 3 correct values.
}
This gets passed to my View which shows the dict_value's correct:
#model Dict.Models.dict_key
#using (Html.BeginForm())
{
<div>Key: #Model.name </div>
<table class="table">
<tr>
<th>Language</th>
<th>Text</th>
</tr>
#for (var i = 0; i < Model.dict_value.Count(); i++)
{
<tr>
<td> #Model.dict_value.ElementAt(i).dict_lang.name_en </td>
<td> #Html.EditorFor(x => x.dict_value.ElementAt(i).value) </td>
</tr>
}
<div class="form-group">
<input type="submit" value="Save" />
</div>
</table>
}
When submitting my changes back to the controller...
[HttpPost]
public async Task<ActionResult> Texts(dict_key dict_key)
{
if (ModelState.IsValid)
{
//Also tried: db.Entry(dict_key).State = EntityState.Modified;
db.Entry(dict_key.dict_value).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Texts");
}
return View(dict_key);
}
..then my "dict_key" is totally different from the object I passed to my edit-view. The passed object contained the collection of dict_value's and the "returned" and edited object returns with the proper key object, but with an empty dict_value collection.
I try to avoid using a userdefined model or the viewbag to do all of that stuff manually. What is the best practise solution for this?
Collection.ElementAt doesn't generate a proper field name in Razor. You need a List. Here you should use a view model instead of your entity directly and simply make your dict_value collection a List<dict_value> there.
Alternatively, you can create an editor template for dict_value and then in your view just do:
#Html.EditorFor(m => m.dict_value)
Where dict_value there is your entire collection. Razor will render an instance of the editor template for each member of the collection and properly index everything.

Insert Data to tblEducation using asp.net mvc 2.0

I have 2 tables in database:tbleducation,tblemployee.Anyway for table tblemployee, I have fields: employeeID,employeeName....I want to insert data into tbleducation that have fields such as:EmployeeID,Duration,.....And for the EmployeeID of table tbleducation I want to do the dropdownlist that list all EmployeeName in tblEmployee into dropdownlist.And I have code as below:
View
<div id="Education">
<%Html.EnableClientValidation(); %>
<% using (Html.BeginForm("Education","EmployeeProfile")){%>
<% Html.ValidationSummary(true, "Unsuccessfull"); %>
<table>
<tr>
<td>Employee Name</td>
<td><%= Html.DropDownListFor(x => x.EmployeeName, Model.Employee, "select EmployeeName")%</td>
<td>Duration</td>
<td><%: Html.TextBoxFor(m=> m.Duration, new { id="duration",name="duration"})%>
<%: Html.ValidationMessageFor(m => m.Duration) %></td>
<tr>
<td><input type="submit" name="add" id="add" value="Add" /></td>
</tr>
</table>
<%}%>
</div>
Model
public class UserModels
{
public string EmployeeName { get; set; }
public int EmployeeCode { get; set; }
public IEnumerable<SelectListItem> Employee { set; get; }
}
Controller
public ActionResult Education() {
var query = (from e in context.tblEmployee_Employee
select new
{
empID = e.Code,
EmpName = e.NameEng
}
).ToList();
var model = new UserModels();
var _Emp = query;
foreach (var item in _Emp)
{
model.EmployeeCode = item.empID;
model.EmployeeName = item.EmpName;
model.Employee = new SelectList(_Emp, "EmpName", "EmpName");
}
return View(model);
}
[HttpPost]
public ActionResult Education(UserModels model, FormCollection edu) {
tblEmployee_Education education = new tblEmployee_Education();
education.Duration = edu["Duration"].ToString();
education.Certificate = edu["Certificate"].ToString();
education.Country = edu["Country"].ToString();
education.SchoolName = edu["SchoolName"].ToString();
education.Major = edu["Major"].ToString();
education.SubDescript = edu["SubDescript"].ToString();
string EName = edu["EmployeeName"].ToString();
return Content(
string.Format(
"Selected role for {0} is {1}", model.EmployeeName, model.EmployeeCode
)
);
context.AddTotblEmployee_Education(education);
context.SaveChanges();
return View("Personal");
}
I got the warning message "unreachble code detected".I really do not know how to solve it.Please kindly help me,
Thanks in advanced,
In your POST action, here:
return Content(
string.Format(
"Selected role for {0} is {1}", model.EmployeeName, model.EmployeeCode
)
);
you have already returned a result and the action execution ends.
So get rid of the lines that follow it, they will never be executed:
context.AddTotblEmployee_Education(education);
context.SaveChanges();
return View("Personal");
And if you want them to be executed, then remove the return Content(...) line.

Why when I pass a Lambda expressin Func thats give me an error

When I pass call a Generic Method that return A Func and pass in parameter of the Where, that's dosen't work. (System.InvalidOperationException: Internal .NET Framework Data Provider error 1025.)
The error is when I want to get the Role information.
For the Role, I need to perform a Where Clause Expression EX: (p => p.LangID == 1)
This code dosen't Work
In the repository
public Func<T, bool> GetLmbLang<T>() where T:class,IBaseGenericTxt
{
int lang = -1;
lang = Convert.ToInt32(HttpContext.Current.Session["Language"]);
return (p => p.LangID == lang);
}
In the controller
var ViewModel = _db.Contacts.Where(a=> a.IsActive == true).Select(a => new ContactListViewModel {
ContactID = a.ContactID,
ContactName = a.ContactName,
Role = a.ContactType.ContactTypeTexts.Where(repGeneric.GetLmbLang<ContactTypeText>()).Select(af => af.Txt).FirstOrDefault(),
CompanyType = a.Supplier.SupplierName,
Addr = a.Address ,
Email = a.ContactEmail,
Phone = a.ContactPhone
}).ToList();
for (int i = 0; i < ViewModel.Count(); i++)
{
Response.Write(ViewModel.ElementAt(i).ContactID + "<br />");
}
This code WORK
int lang = -1;
lang = Convert.ToInt32(Session["Language"]);
var ViewModel = _db.Contacts.Where(a=> a.IsActive == true).Select(a => new ContactListViewModel {
ContactID = a.ContactID,
ContactName = a.ContactName,
Role = a.ContactType.ContactTypeTexts.Where(p => p.LangID == lang).Select(af => af.Txt).FirstOrDefault(),
CompanyType = a.Supplier.SupplierName,
Addr = a.Address ,
Email = a.ContactEmail,
Phone = a.ContactPhone
}).ToList();
for (int i = 0; i < ViewModel.Count(); i++)
{
Response.Write(ViewModel.ElementAt(i).ContactID + "<br />");
}
My ContactListViewModel
public class ContactListViewModel
{
public int ContactID { get; set; }
public string ContactName { get; set; }
public string Role { get; set; }
public string Company { get; set; }
public string CompanyType { get; set; }
public Address Addr { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
My List View
..... Inherits="System.Web.Mvc.ViewPage<List<mvcinfosite.ViewModels.ContactListViewModel>>" %>
<table class="genTable">
<% for (int i = 0;i < Model.Count; i++) { %>
<tr>
<td>
<%: Html.ActionLink(item.ContactName, "Edit", new { id=item.ContactID }) %>
</td>
<td>
<%: item.Role %>
</td>
<td>
<%: item.Company %>
</td>
<td>
<%: item.CompanyType %>
</td>
<td>
<%: GlobalHelper.GetAddress(item.Addr) %>
</td>
<td>
<%: item.Email %>
</td>
<td>
<%: item.Phone %>
</td>
</tr>
<% } %>
</table>
As naasking points out, you need to use an Expression of a Func instead of a straight Func:
public Expression<Func<T, bool>> GetLmbLang<T>() where T:class,IBaseGenericTxt
{
int lang = -1;
lang = Convert.ToInt32(HttpContext.Current.Session["Language"]);
return (p => p.LangID == lang);
}
Edit
Ah, yes, well the problem is that your function doesn't actually know what class it's working with at compile time: it only knows that it's a class, and it implements IBaseGenericTxt. So when you say p.LangId, that part of the expression is calling IBaseGenericTxt.LangId, and not ContactTypeText.LangId.
You'll need to build your own expression tree in order to get this to work right. Something like this:
var paramExpr = Expression.Parameter(typeof(T), "p");
return Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(paramExpr, "LangId"),
Expression.Constant(lang)),
paramExpr);
Edit 2
Two things:
Because LINQ to Entities will try to take anything in a query expression and convert it to a SQL statement, you have to be careful not to go calling methods in the middle of your query. You'll want to call the GetLmbLang method first and store its value in a variable to use in the query.
As you point out in your comment, because the ContactTypeTexts property does not implement IQueryable, this gets particularly tricky. You have three options as far as I can tell:
Create your entire select statement as an expression tree. This is very annoying and error-prone.
Use Joe Albari's LinqKit to "Compile" and "Expand" your query. LinqKit will traverse the expression tree and build a new tree wherein your query Expression is converted to its equivalent Func.
Go back to your data context rather than using the ContactTypeTexts property.
Personally, I would probably go with the last option, like this:
var lambdaLang = repGeneric.GetLmbLang<ContactTypeText>();
var ViewModel = _db.Contacts
.Where(a=> a.IsActive == true)
.Select(a => new ContactListViewModel {
ContactID = a.ContactID,
ContactName = a.ContactName,
Role = _db.ContactTypeTexts
.Where(ct => ct.ContactType.Contacts.Any(
c => c.ContactId == a.ContactId)
.Where(lambdaLang)
.Select(af => af.Txt).FirstOrDefault(),
CompanyType = a.Supplier.SupplierName,
Addr = a.Address ,
Email = a.ContactEmail,
Phone = a.ContactPhone
}).ToList();
The latter code works because the C# compiler converts it into an expression tree, ie. System.Linq.Expression, whereas your original code was compiled as a Func. Linq to SQL as currently designed cannot process the Func, only expression trees.

ModelBinder NHibernate Complex Object with Collections

Below, on initial load (Edit), everything displays fine. However, when I POST (Action below), it looks like it goes and tries to grab the ProductAttribute models separately, with the Product's id, which promptly fails. How to keep my Binder implementation from trying to re-bind Collections as separate entities?
Thanks!
Model
public class Product {
virtual public long Id { get; set; }
virtual public string Name { get; set; }
private IList<ProductAttribute> _productAttributes;
public virtual IList<ProductAttribute> ProductAttributes {
get{
if(_productAttributes == null){
_productAttributes = new List<ProductAttribute>();
}
return _productAttributes;
}
set{
_productAttributes = value;
}
}
}
View
<%using (Html.BeginForm(new {id = Model.Id > 0 ? (long?)Model.Id : null})) {%>
<table class="form">
<% for(var i=0; i < Model.ProductAttributes.Count; i++){
var pa = Model.ProductAttributes[i]; %>
<tr>
<th><%: Model.ProductAttributes[i].Name %></th>
<td>
<%: Html.Hidden("ProductAttributes.Index", i) %>
<% if(pa.CanSpecifyValueDirectly()){ %>
<%: Html.TextBoxFor(model => model.ProductAttributes[i].Value) %>
<% } else { %>
<%: Html.DropDownListFor(model => model.ProductAttributes[i].Value, new SelectList(pa.MarketAttribute.AttributeLevels, "id", "Name", pa.AttributeLevel)) %>
<% } %>
</td>
</tr>
<input type="submit" value="Save" />
</table>
<%}%>
Controller
public ActionResult Edit(long id, Product product) {
ViewData.Model = product;
if (ModelState.IsValid) {
var results = product.Update();
ViewData["results"] = results;
if (!results.Error) {
return RedirectToAction("Show", new { id = id });
}
}
return View();
}
Binder
public class StackModelBinder : DefaultModelBinder {
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) {
var modelInterface = modelType.GetInterface("IModel");
if (modelInterface == null) {
return base.CreateModel(controllerContext, bindingContext, modelType);
}
var value = bindingContext.ValueProvider.GetValue("id").RawValue.ToString();
if (string.IsNullOrEmpty(value)) {
return base.CreateModel(controllerContext, bindingContext, modelType);
}
var id = Convert.ChangeType(value, typeof (long));
var assembly = Assembly.GetAssembly(modelType);
var dao = assembly.GetType(string.Concat(assembly.GetName().Name, ".core.GlobalDao`1[", modelType.FullName, "]"));
if (dao == null) {
return base.CreateModel(controllerContext, bindingContext, modelType);
}
var method = dao.GetMethod("Get");
return method.Invoke(null, new[] {id});
}
}
Typically, it is a bad idea to push entities through the model binder--they tend to be a bit too complex for it to handle, never mind the exciting stuff that goes on in modern ORMs, such as dynamic proxies, that can give the ModelBinder or the ORM fits.
Your best bet here is to change the rules and build a dedicated class for taking the edits and transferring that to the controller. This class can be ModelBinder-friendly and you get the added benefit of separating the UI from the domain entities.