Should I still see the query hit in SQL Profiler? - sql-server

I am currently building a web site and I just implemented SqlCacheDependency using LinqToSQL like so.
public IQueryable<VictoryList> GetVictoryList()
{
string cacheKey = HttpContext.Current.User.Identity.Name + "victoryCacheKey";
IQueryable<VictoryList> cachednews = (IQueryable<VictoryList>)HttpContext.Current.Cache.Get(cacheKey);
if (cachednews == null)
{
var results = from v in _datacontext.ViewVictoryLists
orderby _datacontext.GetNewId()
select new VictoryList
{
MemberID = v.MemberID,
Username = v.Aspnetusername,
Location = v.Location,
DaimokuGoal = v.DaimokuGoal,
PreviewImageID = v.PreviewImageID,
TotalDaimoku = v.TotalDaimoku,
TotalDeterminations = v.TotalDeterminations,
DeterminationID = v.DeterminationID,
DeterminationName = v.DeterminationName
};
SqlCacheDependency dependency =
new SqlCacheDependency(_datacontext.GetCommand(results) as SqlCommand);
HttpContext.Current.Cache.Add(cacheKey, results, dependency, DateTime.MaxValue,
TimeSpan.Zero, CacheItemPriority.Normal, null);
return results.ToList().AsQueryable();
}
return cachednews;
}
It appears to be working as things are noticbly faster especially on some complex queries, however while looking at things in SQLProfiler I still see the query run through, I'm using the CommandBroker mode of SqlCacheDependency. Should I still see the query even though the data is obviously coming from a cached object?

I think that the problem is that you are storing IQueryable's in your cache, and then cachednews contains an IQueryable that hits the database.
Try the following changes.
public IQueryable<VictoryList> GetVictoryList() {
// ...
if (cachednews == null)
{
var results = from // ...
results = results.ToList().AsQueryable(); // force query execution
SqlCacheDependency dependency = // ...;
HttpContext.Current.Cache.Add(cacheKey,
results, // now just the result are stored
dependency,
DateTime.MaxValue,
TimeSpan.Zero,
CacheItemPriority.Normal,
null);
return results;
}
return cachednews;
}

Related

Multiple entries on DbUpdateException when one is expected

I sync data from an api and detect if an insert or update is necessary.
From time to time I receive DbUpdateExceptions and then fallback to single insert/update + savechanges instead of addrange/updaterange + savechanges.
Because single entities are so slow I wanted to only remove the failing entity from changetracking and try to save it all again, but unfortunately mssql returns all entities instead of only the one that is failing in DbUpdateException.Entries.
Intellisense tells me
Gets the entries that were involved in the error. Typically this is a single entry, but in some cases it may be zero or multiple entries.
Interestingly this is true if I try it on a mysql server. There only one entity is returned, but mssql returns all, which makes it impossible for me to exclude only the failing one.
Is there any setting to change mssql behaviour?
Both mysql and mssql are azure hosted resources.
Here an example:
var addList = new List<MyEntity>();
var updateList = new List<MyEntity>();
//load existing data from db
var existingData = Context.Set<MyEntity>()
.AsNoTracking()
.Take(2).ToList();
if (existingData.Count < 2)
return;
//addList
addList.Add(new MyEntity
{
NotNullableProperty = "Value",
RequiredField1 = Guid.Empty,
RequiredField2 = Guid.Empty,
});
addList.Add(new MyEntity
{
NotNullableProperty = "Value",
RequiredField1 = Guid.Empty,
RequiredField2 = Guid.Empty,
});
addList.Add(existingData.ElementAt(0)); //this should fail due to duplicate key
addList.Add(new MyEntity
{
NotNullableProperty = "Value",
RequiredField1 = Guid.Empty,
RequiredField2 = Guid.Empty,
});
//updateList
existingData.ElementAt(1).NotNullableProperty = null; //this should fail due to invalid value
updateList.Add(existingData.ElementAt(1));
//save a new entity that should fail
var newKb = new MyEntity
{
NotNullableProperty = "Value",
RequiredField1 = Guid.Empty,
RequiredField2 = Guid.Empty,
};
Context.Add(newKb);
Context.SaveChanges();
newKb.NotNullableProperty = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; //this should fail due to length
updateList.Add(newKb);
try
{
if (addList.IsNotNullOrEmpty())
context.Set<MyEntity>().AddRange(addList);
if (updateList.IsNotNullOrEmpty())
context.Set<MyEntity>().UpdateRange(updateList);
context.SaveChanges();
}
catch (DbUpdateException updateException)
{
//updateException.Entries contains all entries, that were added/updated although only three should fail
}

Objectify return List & Cursor

I am trying to use a cursor with Objectify and Google App Engine to return a subset of data and a cursor so that I can retrieve more data when the user is ready. I found an example here that looks exactly like what I need but I don't know how to return the final list plus the cursor. Here is the code I have:
#ApiMethod(name = "listIconThemeCursor") //https://code.google.com/p/objectify-appengine/wiki/Queries#Cursors
public CollectionResponse<IconTheme> listIconThemeCursor(#Named("cursor") String cursorStr) {
Query<IconTheme> query = ofy().load().type(IconTheme.class).limit(10);
if (cursorStr != null ) {
query.startAt(Cursor.fromWebSafeString(cursorStr));
}
List<IconTheme> result = new ArrayList<IconTheme>();
int count = 0;
QueryResultIterator<IconTheme> iterator = query.iterator();
while (iterator.hasNext()) {
IconTheme theme = iterator.next();
result.add(theme);
count++;
}
Cursor cursor = iterator.getCursor();
String encodeCursor = cursor.toWebSafeString();
return serial(tClass, result, encodeCursor);
}
Note that this was modified from a previous endpoint in which I returned the CollectionResponse of ALL the data. My dataset is large enough that this is no longer practical. Basically, I don't know what was in the user's function of 'serial(tClass, result, encodeCursor) that let it get returned to the user.
There is another example here but it doesn't appear to answer my question either.
I don't quite understand what you are asking, but I see one immediate bug in your code:
query.startAt(Cursor.fromWebSafeString(cursorStr));
...should be:
query = query.startAt(Cursor.fromWebSafeString(cursorStr));
Objectify command objects are immutable, functional objects.
After a long slog, I figured out that CollectionResponse has the cursor in it :(
Here is the complete code I used incorporating the comment from stickfigure above:
#ApiMethod(name = "listIconThemeCursor", path="get_cursor")
public CollectionResponse<IconTheme> listIconThemeCursor(#Named("cursor") String cursorStr) {
Query<IconTheme> query = ofy().load().type(IconTheme.class)
.filter("errors <", 10)
.limit(10);
if (cursorStr != null ) {
query = query.startAt(Cursor.fromWebSafeString(cursorStr));
}
List<IconTheme> result = new ArrayList<IconTheme>();
QueryResultIterator<IconTheme> iterator = query.iterator();
while (iterator.hasNext()) {
IconTheme theme = iterator.next();
result.add(theme);
}
Cursor cursor = iterator.getCursor();
CollectionResponse<IconTheme> response = CollectionResponse.<IconTheme> builder()
.setItems(result)
.setNextPageToken(cursor.toWebSafeString())
.build();
return response;
}

Audit of what records a given user can see in SalesForce.com

I am trying to determine a way to audit which records a given user can see by;
Object Type
Record Type
Count of records
Ideally would also be able to see which fields for each object/record type the user can see.
We will need to repeat this often and for different users and in different orgs, so would like to avoid manually determining this.
My first thought was to create an app using the partner WSDL, but would like to ask if there are any easier approaches or perhaps existing solutions.
Thanks all
I think that you can follow the documentation to solve it, using a query similar to this one:
SELECT RecordId
FROM UserRecordAccess
WHERE UserId = [single ID]
AND RecordId = [single ID] //or Record IN [list of IDs]
AND HasReadAccess = true
The following query returns the records for which a queried user has
read access to.
In addition, you should add limit 1 and get from record metadata the object type,record type, and so on.
I ended up using the below (C# using the Partner WSDL) to get an idea of what kinds of objects the user had visibility into.
Just a quick'n'dirty utility for my own use (read - not prod code);
var service = new SforceService();
var result = service.login("UserName", "Password");
service.Url = result.serverUrl;
service.SessionHeaderValue = new SessionHeader { sessionId = result.sessionId };
var queryResult = service.describeGlobal();
int total = queryResult.sobjects.Count();
int batcheSize = 100;
var batches = Math.Ceiling(total / (double)batcheSize);
using (var output = new StreamWriter(#"C:\test\sfdcAccess.txt", false))
{
for (int batch = 0; batch < batches; batch++)
{
var toQuery =
queryResult.sobjects.Skip(batch * batcheSize).Take(batcheSize).Select(x => x.name).ToArray();
var batchResult = service.describeSObjects(toQuery);
foreach (var x in batchResult)
{
if (!x.queryable)
{
Console.WriteLine("{0} is not queryable", x.name);
continue;
}
var test = service.query(string.Format("SELECT Id FROM {0} limit 100", x.name));
if(test == null || test.records == null)
{
Console.WriteLine("{0}:null records", x.name);
continue;
}
foreach (var record in test.records)
{
output.WriteLine("{0}\t{1}",x.name, record.Id);
}
Console.WriteLine("{0}:\t{1} records(0)", x.name, test.size);
}
}
output.Flush();
}

RIA-Services - how to WhereOr or use an IN style construct

I am using SL 4, WCF RIA Services against Entity Framework 4.0. I have an Entity, Visit, that has a string Status field. I have a search screen where I need to display results that have StatusA or StatusB. I am struggling to find a way to specify a client-side query that specifies a collection of statuses that should be matched. If I was to write what I want in SQL it would look something like:
select * from Visit where Status in ('StatusA', 'StatusB');
Client side, it appears to be straightforward to chain Where methods for a WhereAnd effect:
var query = this.PqContext.GetVisitsQuery();
if (!string.IsNullOrEmpty(this.PracticeName))
{
query = query.Where(v => v.PracticeName.ToUpper().Contains(this.PracticeName.ToUpper()));
}
if (this.VisitDateAfter.HasValue)
{
query = query.Where(v => v.VisitDate > this.VisitDateAfter);
}
if (this.VisitDateBefore.HasValue)
{
query = query.Where(v => v.VisitDate < this.VisitDateBefore);
}
However, I can't seem to find a straightforward way to do a WhereOr style operation. I have tried this:
var statuses = new List<string>();
if (this.ShowStatusA)
{
statuses.Add("StatusA");
}
if (this.ShowStatusB)
{
statuses.Add("StatusB");
}
if (statuses.Any())
{
query = query.Where(BuildContainsExpression<Visit, string>(e => e.Status, statuses));
}
Where BuildContainsExpression looks like:
private static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
{
if (null == valueSelector)
{
throw new ArgumentNullException("valueSelector");
}
if (null == values)
{
throw new ArgumentNullException("values");
}
ParameterExpression p = valueSelector.Parameters.Single();
if (!values.Any())
{
return e => false;
}
var equals =
values.Select(
value =>
(Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
var body = equals.Aggregate<Expression>(Expression.Or);
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
But this throws a "Bitwise operators are not supported in queries." exception. Any clues? Is there an alternative way to build an expression tree that works here or do I need to pass all the parameters over to the server and use the BuildContainsExpression there?
Your time and your guidance are much appreciated.
You can create a query method such as the following in your domain service:
GetVisitsByStatus(string[] statusList) {
// create the LINQ where clause here
}
And then from the client, call context.GetVistsByStatusQuery(string[]).
Not all of LINQ is (or even can) be exposed over the URL, so there are always cases where you need to use simple parameters, and have the middle tier construct the LINQ expressions that eventually define the query that goes to the back-end data store.
Hope that helps.

SqlCacheDependecy command notification not working

I been trying to get sqlcachedependecy working, but it doesn't appear to work
I got the proper settings in my web.config and also global.asa, however when I run this query and the changes are made to the database from either with in or outside the web site the cached objects are not updated please someone help? I know its not because this query is querying a view, because I tested this using straight SqlDependecy and the notification works fine.
public IQueryable<VictoryList> GetVictoryList()
{
string cacheKey = HttpContext.Current.User.Identity.Name + "victoryCacheKey";
IQueryable<VictoryList> cachednews = (IQueryable<VictoryList>)HttpContext.Current.Cache.Get(cacheKey);
if (cachednews == null)
{
var results = from v in _datacontext.ViewVictoryLists
orderby _datacontext.GetNewId()
select new VictoryList
{
MemberID = v.MemberID,
Username = v.Aspnetusername,
Location = v.Location,
DaimokuGoal = v.DaimokuGoal,
PreviewImageID = v.PreviewImageID,
TotalDaimoku = v.TotalDaimoku,
TotalDeterminations = v.TotalDeterminations,
DeterminationID = v.DeterminationID,
DeterminationName = v.DeterminationName
};
results = results.ToList().AsQueryable();
SqlCacheDependencyAdmin.EnableNotifications(_datacontext.Connection.ConnectionString);
SqlCacheDependency dependency =
new SqlCacheDependency(_datacontext.GetCommand(results) as SqlCommand);
HttpContext.Current.Cache.Insert(cacheKey, results, dependency);
return results;
}
return cachednews;
}
According to the stated Limitations for creating a query for notification, listed at msdn...
The statement must not reference a view.

Resources