Stuffing an anonymous type in ViewBag causing model binder issues - entity-framework

can someone tell me what I'm doing wrong? :-)
I have this simple query:
var sample = from training in _db.Trainings
where training.InstructorID == 10
select new { Something = training.Instructor.UserName };
And I pass this to ViewBag.
ViewBag.Sample = sample;
Then I want to access it in my view like this:
#foreach (var item in ViewBag.Sample) {
#item.Something
}
And I get error message 'object' does not contain a definition for 'Something'. If I put there just #item, I get result { Something = SomeUserName }
Thanks for help.

This cannot be done. ViewBag is dynamic and the problem is that the anonymous type is generated as internal. I would recommend you using a view model:
public class Instructor
{
public string Name { get; set; }
}
and then:
public ActionResult Index()
{
var mdoel = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
return View(model);
}
and in the view:
#model IEnumerable<Instructor>
#foreach (var item in ViewBag.Sample) {
#item.Something
}

If you want to send in ViewData For example and don't want to send in model
you could use the same could as in the upper answer
and in the Controller
enter code here
ViewData[Instractor] = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
and in the view you need to cast this to
`IEnumerable<Instructor>`
but to do this you should use
#model IEnumerable<Instructor>
Then you could do something like this
IEnumerable<instructors> Instructors =(IEnumerable<Instructor>)ViewData[Instractor];
then go with foreach
#foreach (var item in Instructors ) {
#item.Something
}

Related

How can i use Custom query Single field in EFCore?

In EF6, there is context.Database.sqlquery that I can use. Why does EF Core cancel this?
I try to find the answer but the context.user.FromInterpolated doesn't allow select Single field. (Or am I using the wrong method of this?)
Here is my code. Please give me some advice that I can solve this problem.
[HttpPost]
[Obsolete]
public async Task<IActionResult> SendEmail()
{
Email email = new Email();
var ID = HttpContext.Request.Form["ID"].ToString();
var Title = HttpContext.Request.Form["Title"].ToString();
var Body = HttpContext.Request.Form["Body"].ToString();
var Emails = context.user.FromSqlInterpolated($"select email from user where UserId in({ID})");
foreach (var item in Emails)
{
if (!string.IsNullOrEmpty(item.Email))
{
email.Send(item.Email, Title, Body);
}
}
await HttpResponseWritingExtensions.WriteAsync(this.Response, "success");
return RedirectToAction(nameof(Index));
}
You can do something like this:
public class StringReturn
{
public string Value { get; set; }
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity<StringReturn>().HasNoKey();
}
using (var db = new NorthwindContext())
{
var result = db.Set<IntReturn>()
.FromSqlRaw("exec dbo.Scalar")
.AsEnumerable()
.First().Value;
Console.WriteLine(result);
}
See my blog post here for more info: https://erikej.github.io/efcore/2020/05/26/ef-core-fromsql-scalar.html
Ok first of all you have sql injection in your code. So if user pass in field id smth like 1 ) or ( 1=1 . It will allow it and that is basic not very harmfull in your case but
What you should really do is
var ids= HttpContext.Request.Form["ID"].ToString().Split(",", StringSplitOptions.RemoveEmptyEntries).ToList();
if(ids.Any()){
var Emails = await context.user.Where(u=>ids.Contains(u.UserId)).Select(u=>u.email).ToListAsync();
}

Order By in Linq to Entities

I had sql table with two columns sizename and orderof . I want to select from that table all the sizenames but in ascending order of the orderof .Iam using EF6 and Linq to Entities
I had used the Query Like this .But its not working(sorting)
var sizedetails = (from size in enty.StyleSizes
where size.OurStyleID == ourstyleid
orderby size.Orderof
select new
{
size.SizeName
}).Distinct();
//var sizedetails = enty .StyleSizes.Where(u => u.OurStyleID == ourstyleid).Select(u => u.SizeName ).Distinct();
foreach (var sizedet in sizedetails)
{
dt.Columns.Add(sizedet.SizeName.Trim(), typeof(String));
}
I know this may be already asked. But none of the solution provided in those questions working for me
Since LINQ to Entities translates your query to SQL, ordering before Distinct has no effect. And the problem is that after Distinct you have no access to the property needed for ordering.
So you need an alternative way, which luckily is the GroupBy method - its similar to Distinct but allows you to access the properties of the elements sharing the same key. Thus you can order the result based on some aggregates (in your case looks like Min is the appropriate):
var sizedetails = from size in enty.StyleSizes
where size.OurStyleID == ourstyleid
group size by size.SizeName into sizeGroup
orderby sizeGroup.Min(size => size.Orderof)
select new
{
SizeName = sizeGroup.Key
};
I dint tried with DB but with in memory collection it gives be correct result .
here is my class .
class StyleSizes
{
public int Orderof { get; set; }
public string SizeName { get; set; }
public int OurStyleID { get; set; }
}
// logic to ue orderby
var list = new List<StyleSizes> { new StyleSizes { Orderof=2,SizeName="B",OurStyleID=1 },
new StyleSizes { Orderof=11,SizeName="C" ,OurStyleID=2},
new StyleSizes { Orderof=9,SizeName="D" ,OurStyleID=1},
new StyleSizes { Orderof=9,SizeName="D" ,OurStyleID=1},
new StyleSizes { Orderof=3,SizeName="E" ,OurStyleID=1},
new StyleSizes { Orderof=4,SizeName="F" ,OurStyleID=1}
};
var orderList = list.Where(x=>x.OurStyleID==1).OrderBy(x => x.Orderof).Select(c => new { c.SizeName }).Distinct();

MVC3: delete an object in an database from an array of selected objects

I've successfully selected the Objects I want to delete. But the problem is when I remove an item from Object array, it doesn't make any changes. My code is following below..
My database
public List<Product> db = new ProductRepository().GetProducts();
Here it shows all the products with checkbox..
public ActionResult MultipleDeletes()
{
return View(db);
}
On Submitting "Button named Delete", I got problem.
[HttpPost]
public ActionResult MultipleDeletes(int[] selectedProducts)
{
var del_products = from x in selectedProducts
from y in db
where y.ProductId == x
select y;
foreach (var item in del_products)
{
//Product p = db.Find(item.ProductId);
//db.Remove(p);
//db.SaveChanges();
}
return View(db);
}
Could anyone help me?
can you also tell me, how to write Lambda expression instead of LinQ?
I think in this case you need to make use of Delete rather than remove.
Use following and see if it works
db.DeleteObject(p)
db.SaveChanges()
The problem was in the model. I used NBuilder.. so it didn't really save the data.
I built an DbContext. Then it worked.
Solution is ..
public ProductDBContext db = new ProductDBContext();
[HttpPost]
public ActionResult MultipleDeletes(int[] selectedProducts)
{
foreach (int item in selectedProducts)
{
Product product = db.Where(p => p.ProductId == item).SingleOrDefault();
db.Remove(product);
db.SaveChanges();
}
return View();
}

How to filter bad words of textbox in ASP.NET MVC?

I have a requirement in which i wanna filter the textbox value, that is should remove the bad words entered by the user. Once the user enters the bad words and click on submit button, action is invoked. Somewhere in the model(any place) i should be able to remove the bad words and rebind the filtered value back to the model.
How can i do this?
If you can update the solution to MVC 3 the solution is trivial. Just implement the word check in a controller and then apply the RemoteAttribute on the property that should be validated against bad words. You will get an unobtrusive ajax check and server side check with just one method and one attribute. Example:
public class YourModel
{
[Remote("BadWords", "Validation")]
public string Content { get; set; }
}
public class ValidationController
{
public JsonResult BadWords(string content)
{
var badWords = new[] { "java", "oracle", "webforms" };
if (CheckText(content, badWords))
{
return Json("Sorry, you can't use java, oracle or webforms!", JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
private bool CheckText(string content, string[] badWords)
{
foreach (var badWord in badWords)
{
var regex = new Regex("(^|[\\?\\.,\\s])" + badWord + "([\\?\\.,\\s]|$)");
if (regex.IsMatch(content)) return true;
}
return false;
}
}

Using DataAnnotations (DisplayColumn) in WCF RIA Services

I have created an entity framework 4.0 (DB-First) model, added my partial classes and used DataAnnotations on them to have a perfect UI on the client.
I have some relations between my tables and used DisplayColumn on top my classes. e.g. I have a User class that has [DataColumn("UserName")] attribute on top of the class. And a Message class which has "public User Sender" which has [Include] attribute on top of the property.
Also, I have used .Include("User") in my DomainService to load the User who's related to a message.
But in my datagrid, I see User : (UserID) (UserID=Key property of User entity) instead of UserName that I have specified. I looked in the generated code in my SL project and it correctly decorated my User class with DisplayColumn attribute. But still, I cannot see UserName in my grid.
Any help would be greatly appreciated.
Update: Here's my question in code:
As I have mentioned, Owner, UserName, MessageId, UserId have been defined in my auto-generated model. UserMeta class has nothing special.
[MetadataType(typeof(MessageMeta))]
public partial class Message
{
}
public class MessageMeta
{
[Include()]
[Display(Name = "Belongs to", Order = 4)]
[Association("Message_User","MessageId","UserId",IsForeignKey = true)]
public virtual User Owner { get; set; }
}
[MetadataType(typeof(UserMeta))]
[DisplayColumn("UserName")]
public partial class User
{
}
In my DomainService:
public IQueryable<Message> GetMessages()
{
return this.ObjectContext.Messages.Include("Owner");
}
At last, I had to use Reflection. For DataGrid:
private void OnAutoGenerateColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
//Need to get an array, but should always just have a single DisplayColumnAttribute
var atts = e.PropertyType.GetCustomAttributes(typeof(DisplayColumnAttribute),true);
foreach (DisplayColumnAttribute d in atts)
{
DataGridTextColumn col = (DataGridTextColumn)e.Column;
//Make sure that we always have the base path
if(col.Binding.Path.Path!="")
{
col.Binding = new Binding()
{
Path = new PropertyPath(col.Binding.Path.Path + "." + d.DisplayColumn)
};
}
//Only do the first one, just in case we have more than one in metadata
break;
}
}
And for Telerik RadGridView:
var column = e.Column as GridViewDataColumn;
if (column == null)
{
return;
}
// Need to get an array, but should always just have a single DisplayColumnAttribute
var atts = column.DataType.GetCustomAttributes(typeof(DisplayColumnAttribute), true);
foreach (DisplayColumnAttribute d in atts)
{
// Make sure that we always have the base path
if (column.DataMemberBinding.Path.Path != "")
{
column.DataMemberBinding = new Binding()
{
Path = new PropertyPath(column.DataMemberBinding.Path.Path + "." + d.DisplayColumn)
};
}
// Only do the first one, just in case we have more than one in metadata
break;
}