I have a nopcommerce website. I find a problem. Please see below code
// My account / Order details page
[HttpsRequirement(SslRequirement.Yes)]
public virtual IActionResult Details(int orderId)
{
var order = _orderService.GetOrderById(orderId);
if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId)
return Challenge();
var orderTotal = order.OrderTotal;
order = _orderService.GetOrderById(orderId);
var orderTotal2 = order.OrderTotal;
var model = _orderModelFactory.PrepareOrderDetailsModel(order);
return View(model);
}
When I put a breakpoint on
var orderTotal = order.OrderTotal;
I get the value (100) of orderTotal from table Order. Then I changed the value of orderTotal from 100 to 200 in the database, and continue to execute the code.
order = _orderService.GetOrderById(orderId);
var orderTotal2 = order.OrderTotal;
This code should get the new value (200) of orderTotal from the table Order, however, it still returns a value of 100 for orderTotal2.
I want to get the refreshed data in function in the controller. Could you help me solve this problem?
Because the GetOrderById Method retrieves the cached order in the memory using 'ToCachedGetById', you can use GetOrderByGuid method instead to get the order directly from DB and skip the caching order
Related
I have a bunch of records that are sorted RANDOMLY, like so:
var entries = DataContext.Entries.OrderBy(e => Random());
The Random function returns a randomly-generated GUID, thereby ordering the records in a random manner. Now my problem is paging. In MVC, I have a List action for the Entry controller that lists the entries:
public class EntryController : Controller
{
public ActionResult List(int page)
{
int pageSize = 10;
var entries = DataContext.Entries.OrderBy(e => Random()).Skip((page - 1) * pageSize).Take(pageSize);
ViewData["entries"] = entries;
return View();
}
}
My problem here is that whenever I go from one page to another page, the entries are REARRANGED ANEW. So when I go to page 1 (step 1), then go to page 2 (step 2), then back to page 1 (step 3), the entries that were shown in the step 1 are different from those shown in step 3. I absolutely need to have the records arranged randomly the first time around, but not in the subsequent look ups.
Any ideas on how best to address this problem?
Because each time you invoke the action the randomness occurs all over again to the whole records before paging, what you need to do is:
Order the records randomly as you want it.
Cache the result.
Fetch the cache every time the action is invoked while applying paging.
public ActionResult List(int page)
{
var dataSource = CacheContext["RandomRecords"];
if(dataSource == null){
dataSource = DataContext.Entries.OrderBy(e => Random());
}
int pageSize = 10;
var entries = dataSource.Skip((page - 1) * pageSize).Take(pageSize);
ViewData["entries"] = entries;
return View();
}
Add a column named sortOrder, being an int.
Do not forget to add a non-unique index on it or sorting on it will be suboptimal.
Put a number there, increased from record to record, not in the same order than your id or an order that would sort the records alphabetically.
Then
dataSource = DataContext.Entries.OrderBy(e => e.sortOrder);
Guids will be slower to sort on, but you can alternatively use a guid column for the task. Every now and then (once per night), you can loop through all records to put new values in the sortOrder column so people will not recognize the order.
You can add following SQL code to get products, you only need to generate some random number and store it into the session or cache and get product again..
DECLARE #NumberOfProductsInDatabase INT
DECLARE #RandomNumber VARCHAR(10)
SET #NumberOfProductsInDatabase = (SELECT COUNT(*) FROM Product)
SET #RandomNumber = '45'
SELECT CAST(100000 * SQRT(EXP(COS(p.SellerId + #RandomNumber))) AS INT) % #NumberOfProductsInDatabase AS RandomProductNr,
p.Id,p.Name,pv.Price,pv.SalePrice
FROM Product p,ProductVariant pv
WHERE pv.ProductId = p.Id
ORDER BY RandomProductNr
I am trying to extract the [key] value from a table.
This is for a logging method which looks like this:
private List<Log> GetAuditRecordsForChange(DbEntityEntry dbEntry, string userId)
{
List<Log> result = new List<Log>();
DateTime changeTime = DateTime.Now;
// Get the Table() attribute, if one exists
TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;
// Get table name (if it has a Table attribute, use that, otherwise get the pluralized name)
string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
// Get primary key value
string keyName = dbEntry.Entity.GetType().GetProperties().Single(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).Name;
if (dbEntry.State == EntityState.Added)
{
result.Add(new Log()
{
LogID = Guid.NewGuid(),
EventType = "A", // Added
TableName = tableName,
RecordID = dbEntry.CurrentValues.GetValue<object>(keyName).ToString(),
ColumnName = "*ALL",
NewValue = (dbEntry.CurrentValues.ToObject() is IDescribableEntity) ? (dbEntry.CurrentValues.ToObject() as IDescribableEntity).Describe() : dbEntry.CurrentValues.ToObject().ToString(),
Created_by = userId,
Created_date = changeTime
}
);
}
The problem is to get the RecordID when a Record is added, when it get deleted or modified it works. (The code to get it is the same)
When I debug I also see that it has the KeyAttribute in the CustomAttributes base but not sure why it always shows up as 0.
I can debug more if needed
After savechanges you can fetch the newly created key. (Guess the key is generated automatically inserting a new record).
for me you have several solutions.
first solution:
enlist added entity from the context
SaveChanges
enumerate the enlisted entities to add log
SaveChanges
the problem (or not) here is that the business and the logging are not in the same transaction.
antother problem, depending on the implementation, is to prevent loging of log of log of log... This can be donne by filtering entities by typeName for example.
other solution:
add and ICollection<Log> to your entities.
the problem here is to unify the logs:
inheritance of entity, or
several log tables + a view
...
other solution
use trigger at database level
other solution
..., use cdc if you have Sql Server Enterprise Edition
Below is the code in question. I receive Object reference not set to an instance of an object. on the where clause inside the Linq query. However, this only happens after it goes through and builds my viewpage.
Meaning: If I step through using debugger, I can watch it pull the correct order I am filtering for, go to the correct ViewPage, fill in the model/table with the correct filtered item, and THEN it comes back to my Controller and shows me the error.
public ActionResult OrderIndex(string searchBy, string search)
{
var orders = repositoryOrder.GetOpenOrderList();
if (Request.QueryString["FilterOrderNumber"] != null)
{
var ordersFiltered = from n in orders
where n.OrderNumber.ToUpper().Contains(Request.QueryString["FilterOrderNumber"].ToUpper().ToString())
select n;
return View(ordersFiltered);
}
return View(orders);
}
its always better to manipulate your strings and other things outside the linq query ,
please refer : http://msdn.microsoft.com/en-us/library/bb738550.aspx
from the readability point of view also its not good ,
public ActionResult OrderIndex(string searchBy, string search)
{
var orders = repositoryOrder.GetOpenOrderList();
var orderNumber = Request.QueryString["FilterOrderNumber"];
if (!string.IsNullOrEmpty(orderNumber))
{
orderNumber = orderNumber.ToUpper();
var ordersFiltered = from n in orders
where n.OrderNumber.ToUpper().Contains(orderNumber)
select n;
return View(ordersFiltered);
}
return View(orders);
}
Your query is not being executed in your Action method because you don't have a ToList (or equivalent) added to your query. When your code returns, your query will be enumerated somewhere in your view and that's the point where the error occurs.
Try adding ToList to your query like this to force query execution in your action method:
var ordersFiltered = (from n in orders
where n.OrderNumber.ToUpper().Contains(Request.QueryString["FilterOrderNumber"].ToUpper().ToString())
select n).ToList();
What's going wrong is that a part of your where clause is null. This could be your query string parameter. Try moving the Request.QueryString part out of your query and into a temporary variable. If that's not the case make sure that your orders have an OrderNumber.
You both were right. Just separately.
This fixed my problem
var ordersFiltered = (from n in orders
where !string.IsNullOrEmpty(n.OrderNumber) && n.OrderNumber.ToUpper().Contains(Request.QueryString["FilterOrderNumber"].ToUpper().ToString())
select n);
I am trying to implement simple membership in my application. My problem is that I want to be able to display the data in the userprofile table for the current user but I dont know how to select it from the DB
I have tried this but I am getting an error:
UserProfile UserP = new UserProfile();
ViewBag.Message = User.Identity.Name;
return View();
UserP = (from r in up.UserName
where up.UserName == User.Identity.Name.ToString()
select r).ToList().FirstOrDefault();
return View(UserP);
Here is the error:
Error 1 Cannot implicitly convert type 'char' to 'MvcApplication5.Models.UserProfile' C:\Users\user\Desktop\MvcApplication5\MvcApplication5\Controllers\HomeController.cs 31 32 MvcApplication5
If I got you right (your code is little bit broken, it has two returns, so I assume there is just two pieces of code), try this:
UserP = (from r in up
where up.UserName == User.Identity.Name.ToString()
select r).FirstOrDefault();
Just get rid of up.UserName in your query. ToList() is also not needed.
P.S. For the future:
I also suggest you adding another column called LoweredUserName and perform checking in the following way:
where up.LoweredUserName == User.Identity.Name.ToString().ToLower()
Here is how you can access the UserProfile.
var context = new UsersContext();
var username = User.Identity.Name;
var user = context.UserProfiles.SingleOrDefault(u => u.UserName == username);
return View(user);
For more on customizing the UserProfile and accessing it read this article.
Hi i'm looking for some help in how to append rows to an existing LINQ object. In the controller method below I have two result sets, i'm looping the Sites and want to add a record to the 'results' object for each record in the Sites object.
I've tried concat etc but not getting anywhere, just need s small example to assist, many thanks in advance, J
public IQueryable<UsersToSite> FindAllUsersToSites(int userId,SystemType obj)
{
var results = (from usersToSite in this._db.UsersToSites
where usersToSite.UserId == userId &&
usersToSite.SystemTypeId == obj
orderby usersToSite.Site.SiteDescription
select usersToSite);
// Now for each remaining Site append a record thats not physically in the database. From the view the user will be able to click these records to ADD new
// I'll then build in a search
var sites = (from site in this._db.Sites
where !(from o in _db.UsersToSites where (o.UserId == userId && o.SystemTypeId == obj) select o.SiteId).Contains(site.SiteId)
orderby site.SiteDescription
select site);
foreach (var site in sites)
{
// HERE I want to create the new ROW in results object
//results = new[results] { new { UsersToSiteId = null, AccessTypeId = null } }.Concat(sites);
//SiteId=site.SiteId,
//UsersToSiteId = 0,
//AccessTypeId = 0,
//UserId = userId
}
return results;
}
I don't think you can, if you want to have keep queryable.
However, if you materialize the results with ToList(), then you can:
var sites = (from site in this._db.Sites
where !(from o in _db.UsersToSites where (o.UserId == userId && o.SystemTypeId == obj) select o.SiteId).Contains(site.SiteId)
orderby site.SiteDescription
select site)
.ToList();
sites.Add(new Site { UsersToSiteId = null, etc });
If it was LINQ to Objects, you could do Concat.
The problem here that it can't do ConcatLINQ query that will have one part from SQL and another from objects. You need to materialize results first and then concat to object.