Not able to return JsonResult - asp.net

The following query is working successfully.
var tabs = (
from r in db.TabMasters
orderby r.colID
select new { r.colID, r.FirstName, r.LastName })
.Skip(rows * (page - 1)).Take(rows);
Now I want to return JsonResult as like
var jsonData = new
{
total = (int)Math.Ceiling((float)totalRecords / (float)rows),
page = page,
records = totalRecords,
rows = (from r in tabs
select new { id = r.colID, cell = new string[] { r.FirstName, r.LastName } }).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
But it will gives me an error like:
The array type 'System.String[]' cannot be initialized in a query result. Consider using 'System.Collections.Generic.List`1[System.String]' instead.
What should I do to get expected result?

I suspect that it's as simple as pushing the last part into an in-process query using AsEnumerable():
var jsonData = new
{
total = (int)Math.Ceiling((float)totalRecords / (float)rows),
page = page,
records = totalRecords,
rows = (from r in tabs.AsEnumerable()
select new { id = r.colID,
cell = new[] { r.FirstName, r.LastName } }
).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
You may want to pull that query out of the anonymous type initializer, for clarity:
var rows = tabs.AsEnumerable()
.Select(r => new { id = r.colID,
cell = new[] { r.FirstName, r.LastName })
.ToArray();
var jsonData = new {
total = (int)Math.Ceiling((float)totalRecords / (float)rows),
page,
records = totalRecords,
rows
};

It's because it's adding to the LINQ query that is your tabs IQueryable. That is then trying to turn the LINQ expression into a SQL query and the provider doesn't support projecting arrays.
You can either change the assignment of the tabs variable's LINQ expression to use ToList to materialize the DB results right then and there, or you can add .AsEnumerable() to the LINQ expression assigned to the rows field of the anonymous type that is your JsonResult. AsEnumerable will demote the IQueryable to an IEnumerable which will prevent your second LINQ query from trying to be added to the DB query and just make it a LINQ-to-objects call like it needs to be.

Related

ASP.NET Entity Framework request SQL

I need to write this SQL statement in Entity Framework:
SELECT
SALARIE.MATRICULE, LIEU, UO, UO_RATTACHEMENT,
PHOTO.PHOTO, SALARIE.NOM, SALARIE.PRENOM
FROM
SALARIE, UNITE_ORG, PHOTO
WHERE
SALARIE.LIEU = UNITE_ORG.UO
I use this method for reading my data :
public JsonResult Read()
{
var nodes = entities.UNITE_ORG.Select(p => new NodeModel { id = p.UO, pid = p.UO_RATTACHEMENT, poste = p.POSTE, img=p.LIB_COMPLET, Fullname=p.RESPONSABLE });
return Json(new { nodes = nodes }, JsonRequestBehavior.AllowGet);
}
I need to change this declaration of nodes.
Thank you
I believe that the equivalent Entity Framework would be the following:
var result = (from s in context.SALARIE
from u in context.UNITE_ORG
from p in context.PHOTO
where s.LIEU == u.UO
select new {
MATRICULE = s.MATRICULE,
LIEU = s.LIEU,
UO = u.UO,
UO_RATTACHEMENT = UO_RATTACHEMENT, // I don't know where this is coming from
PHOTO = p.PHOTO,
NOM = s.NOM,
PRENOM = s.PRENOM
}
);
However, this is just a guess from the information you have giving.
Also, like I have stated in my comment, I really think you should stop using the syntax for cross joins that you are doing (the , seperated syntax)

Asp Core, How to use PagingList<T>.CreateAsync() with a viewModel?

I am working on a asp.net core 1.1 project and i want to create paging in my some views. I studied microsoft documents about paging in asp core but it is very simple mode with 1 table. In my view i use multi table and use a viewmodel to initialize it. I want to use PagingList<T>.CreateAsync() method to create paging but get error:
can not convert from system.linq.Iqueryable<> to system.linq.IorderedQueryable<>
my action:
[HttpGet]
public async Task<IActionResult> Index(int? page)
{
List<BookListViewModel> model = new List<BookListViewModel>();
var query = (from b in _context.books
join a in _context.authors on b.AuthorID equals a.AuthorId
join bg in _context.bookgroups on b.BookGroupID equals bg.BookGroupId
select new
{
b.BookId,
b.BookName,
b.BookPageCount,
b.BookImage,
b.AuthorID,
b.BookGroupID,
a.AuthorName,
bg.BookGroupName
});
foreach (var item in query)
{
BookListViewModel objmodel = new BookListViewModel();
objmodel.BookId = item.BookId;
objmodel.BookName = item.BookName;
objmodel.BookImage = item.BookImage;
objmodel.BookPageCount = item.BookPageCount;
objmodel.AuthorId = item.AuthorID;
objmodel.BookGroupId = item.BookGroupID;
objmodel.AuthorName = item.AuthorName;
objmodel.BookGroupName = item.BookGroupName;
model.Add(objmodel);
}
ViewBag.RootPath = "/upload/thumbnailimage/";
int pageSize = 3;
int pageNumber = (page ?? 1);
return View(await PagingList<BookListViewModel>.CreateAsync(model.AsQueryable() , pageNumber, pageSize));
}
I have not yet written anything about paging in index view and it is a simple list of viewmodel
Well can't really be sure from the code you posted. But the exception says the the CreateAsync method needs IOrderedQueryable, but you're giving it an IQueryable.
Try changing it to pass in the query object (which I guess should implement the IOrderedQueryable, if you're using Entity framework).
The idea behind the PagingList (presumably) is to use it to do the paging in the database.
What you're doing is bringing the filterted set into memory (when for-eaching through the result), and then doing doing the paging.
The code might look something like this:
[HttpGet]
public async Task<IActionResult> Index(int page = 1)
{
var query = (from b in _context.books
join a in _context.authors on b.AuthorID equals a.AuthorId
join bg in _context.bookgroups on b.BookGroupID equals bg.BookGroupId
select new BookListViewModel()
{
BookId = b.BookId,
BookName = b.BookName,
BookPageCount = b.BookPageCount,
BookImage = b.BookImage,
AuthorId = b.AuthorID,
BookGroupId = b.BookGroupID,
AuthorName = a.AuthorName,
BookGroupName = bg.BookGroupName
}).AsNoTracking().OrderBy(u => u.BookId);
ViewBag.RootPath = "/upload/thumbnailimage/";
var pagedResult = await PagingList<BookListViewModel>.CreateAsync(query, 10, page);
return View(pagedResult);
}
Hope it helps.

ASP.NET & SQL Server: won't update but will append/insert

I am using a database-first approach with a custom html helper to get a state of a checkbox using ajax (without using form in the view). I have two tables:
Tbl_1 -> Id, state (true or false), name (name of checkbox)
Tbl_2 -> Id, user_guid, timestamp, Tbl_1Id (foreign_key)
When I do insert operations, it does without any problem but when I try to update it (based upon the logged in user as it also gets GUID, the table gets appended/inserted with new data).
My controller:
public ActionResult SetState(checkboxstate cbstate)
{
var UserId = new Guid(System.Security.Claims.ClaimsPrincipal.Current.FindFirst("sub").Value);
var ent = new StartopDatabaseEntities();
var cbs = ent.checkboxstates.Where(w => w.Name == "World").FirstOrDefault();
if (cbs == null) // when there are no records in the database
{
ent.checkboxstates.Add(cbstate);
ent.checkboxstateUpdates.SingleOrDefault(c => c.Id == cbstate.Id);
var cbsOp = new checkboxstateUpdates();
cbsOp.timestamp = DateTime.Now;
cbsOp.user_guid = UserId;
cbstate.checkboxstateUpdates.Add(cbsOp);
ent.SaveChanges();
} // record in database, update (I've only one user now, so has to update only this one)
else
{
var cbsOp = new checkboxstateUpdates(); // declare in global
var chc = new checkboxstate(); // to be declared in global
var newCbs = ent.checkboxstateUpdates.Include(c => c.checkboxstate).ToList();
foreach (var u in newCbs)
{
if(u.user_guid==UserId && u.CheckboxStateId == u.checkboxstate.Id)
{
chc.state = cbstate.state;
chc.name = cbstate.name;
ent.checkboxstates.Add(chc);
cbsOp.Tidspunkt = DateTime.Now;
cbsOp.OpdateretAfBruger = UserId;
ent.checkboxstateUpdates.Add(cbsOp);
ent.SaveChanges();
}
}
}
Can anyone explain please why it's not updating but appending/inserting same data with a new Id (primary key)? I have a simple view where Ajax sends a call to the controller with the state and name of the checkbox. I have also tried
Db.Entry(obj).state = EntityState.Modified
without any help
You have not written the code for the logic which want to achieve..
I am not clear on the logic of if block also but the else part can be fixed as following.
var newCbs = ent.checkboxstateUpdates.Include(c => c.checkboxstate).Where(u.user_guid == UserId).FirstOrDefault();
if(newCbs != null) {
newCbs.checkboxstate.state = cbstate.state;
newCbs.checkboxstate.name = cbstate.name;
newCbs.Tidspunkt = DateTime.Now;
newCbs.OpdateretAfBruger = UserId;
ent.SaveChanges();
}
Solved this with the help from #David & #Chetan:
I did some modify in the code as per David:
u.checkboxstate.state=cbstate.state;
u.checkboxstate.name=cbstate.name;
u.timestamp=DateTime.Now;
ent.saveChanges();
I was using the wrong logic i.e. getting instance of the class rather than the 'ent' object. Thanks guys for the help.

push data from web form into CRM 2015 with duplicate detection before creating new records inside CRM

Guys.
I have a web form to push metadata into CRM 2015 online by creating new records. But before creating new records in CRM, I would like to check if this records(First Name, Last Name, DOB) duplicate or not. If duplicates, updates the existing record, If not, create a new record.
My current idea is, that on the web form(ASP.NET APP) retrieve all records(Names, DOB) and compare with input metadata, if match, updates or creates new record. But I am not sure if there is simple way to do this.
Do you have any suggestion?
Appreciate it.
I think I just got it.
bool hasDulicate = false;
//duplicate detection
FilterExpression codeFilter = new FilterExpression(LogicalOperator.And);
codeFilter.AddCondition("firstname", ConditionOperator.Equal, firstname.Text);
codeFilter.AddCondition("lastname", ConditionOperator.Equal, lastname.Text);
QueryExpression query = new QueryExpression
{
EntityName = "contact",
ColumnSet = new ColumnSet(true), // we assume you want to retrieve all the fields
Criteria = codeFilter
};
EntityCollection records = service.RetrieveMultiple(query);
int totalrecords = records.Entities.Count;
foreach (Entity record in records.Entities)
{
if (record["emailaddress1"] != null)
{
record["emailaddress1"] = email.Text;
record["mobilephone"] = phone.Text;
proxy.Update(record);
hasDulicate = true;
}
}
if (hasDulicate == false)
{
Entity contact = new Entity("contact");
contact["firstname"] = Convert.ToString(firstname.Text);
contact["lastname"] = Convert.ToString(lastname.Text);
contact["emailaddress1"] = Convert.ToString(email.Text);
contact["mobilephone"] = Convert.ToString(phone.Text);
Guid conid = proxy.Create(contact);
}

Aggregating one side of a many-to-many and bind to gridview in Entity Framework

I have a many-to-many structure in place in my database / Entity Framework model.
CompanyNotice (M-M) CompanyNoticesLocations (M-M) Locations
I am trying to aggregate the Locations for one CompanyNotice and return a comma-separated LocationName for the Locations. I have tried using the following code to aggregate the LocationName:
if (!IsPostBack)
{
using (var context = new ALEntities())
{
var query = from c in context.CompanyNotices.Include("Locations")
select new
{
c.CompanyNoticeHeading,
c.CompanyNoticeText,
c.IsHR,
locations = (from l in c.Locations select l.LocationName).Aggregate((current, next) => string.Format("{0}, {1}", current, next))
};
ASPxGridView1.DataSource = query;
ASPxGridView1.DataBind();
}
}
I get the following error when I try the above code:
LINQ to Entities does not recognize the method 'System.String
Aggregate[String](System.Collections.Generic.IEnumerable1[System.String],
System.Func3[System.String,System.String,System.String])' method, and
this method cannot be translated into a store expression.
When I try:
if (!IsPostBack)
{
using (var context = new ALEntities())
{
var query = from c in context.CompanyNotices.Include("Locations")
select new
{
c.CompanyNoticeHeading,
c.CompanyNoticeText,
c.IsHR,
locations = (from l in c.Locations select l.LocationName)
};
ASPxGridView1.DataSource = query;
ASPxGridView1.DataBind();
}
}
The data within the locations column on the gridview appears as:
System.Collections.Generic.List`1[System.String]
Does anyone know how do I aggregate the LocationName to appear for one CompanyNotice?
Thanks in advance.
you could this ...
using (var context = new ALEntities())
{
var query = from c in context.CompanyNotices.Include("Locations")
select new
{
c.CompanyNoticeHeading,
c.CompanyNoticeText,
c.IsHR,
locations = (from l in c.Locations select l.LocationName)
};
var listed = query.ToList();
var commaListed = listed.Select ( a=> new { a.CompanyNoticeHeading, a.CompanyNoticeText,
commaLines = a.locations.Aggregate((s1, s2) => s1 + "," + s2)});
then bind commaListed to your datagrid

Resources