I am trying to execute query with parameters against local cache or server (if nothing is found in cache).
public async Task<List<T>> Get(IDictionary<string, object> parameters, string resourceName = "", FetchSource fetchSource = FetchSource.None)
{
try
{
var query = resourceName == string.Empty ? EntityQuery.From<T>().WithParameters(parameters) : EntityQuery.From<T>(resourceName).WithParameters(parameters);
var queryResult = await this.ExecuteQuery(query, fetchSource);
var result = queryResult.ToList();
return result;
}
catch (Exception e)
{
return new List<T>(); // return empty result instead
}
}
FetchSource is our enum:
public enum FetchSource
{
None = 0,
FromServer = 1,
FromCache = 2,
FromCacheOrServer = 3
}
And here is ExecuteQuery method:
protected async Task<IEnumerable<T>> ExecuteQuery(EntityQuery<T> query, FetchSource fetchSource = FetchSource.None)
{
//...
if (fetchSource == FetchSource.FromCacheOrServer)
{
var result = query.ExecuteLocally(this.EntityManager); // Throws error
if (result != null && result.Any())
{
return result;
}
return await query.Execute(this.EntityManager);
}
//...
}
When I try to execute query locally this exception is thrown:
{"Unable to cast object of type
'WhereEnumerableIterator`1[StanleySteemer.Nimbus.Client.Common.Model.Proxy.RouteOrder]'
to type
'DataServiceOrderedQuery[StanleySteemer.Nimbus.Client.Common.Model.Proxy.RouteOrder]'."}
Although I couldn't find anything in docs specifically regarding to this subject, I have implemented similar functionality in BreezeJS which was working without issue(UPDATE: it doesn't work correctly):
findWithParametersInCacheOrServer = function (parameters, recordsLimit) {
var query = breeze.EntityQuery
.from(resourceName)
.withParameters(parameters);
var r = executeCacheQuery(query);
if (r) {
if (r.length > recordsLimit) {
return Q.resolve(r);
}
}
return executeQuery(query);
};
function executeCacheQuery(query) {
return entityManagerProvider.manager().executeQueryLocally(query);
}
Data architecture in JavaScript is similar to TempHire example.
Is this a known issue? Is there any workaround for it?
Not sure I understand, neither breeze.js nor breeze.sharp can automatically perform a 'local cache query' that involves parameters. This is because the interpretation of the parameters is only really defined on the server and not on the client.
It sounds as though what you have done is define a custom implementation of your specific 'with parameters' query in breeze.js that completely bypasses Breeze's internal implementation. Is this correct?
Related
Hello I have a common function which looks like below,
public async Task<SPResponse> ExecuteAsync(string spName, DynamicParameters p)
{
SPResponse response = new SPResponse();
using (SqlConnection conn = new SqlConnection(_connStr))
{
conn.Open();
using (SqlTransaction transaction = conn.BeginTransaction(IsolationLevel.ReadCommitted))
{
try
{
p.Add("#SP_MESSAGE", dbType: DbType.String, direction: ParameterDirection.Output, size: 4000);
p.Add("#RETURNSTATUS", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
await conn.ExecuteAsync(sql: spName, param: p, commandType: CommandType.StoredProcedure, transaction: transaction);
response.ReturnMessage = p.Get<string>("#SP_MESSAGE");
response.ReturnStatus = Convert.ToString(p.Get<int>("#RETURNSTATUS"));
if (response.ReturnStatus == "0")
{
response.Ref1 = Convert.ToString(p.Get<int>("#SP_ID"));
transaction.Commit();
}
else
{
transaction.Rollback();
}
}
catch (Exception ex)
{
Utils.Logger.Instance.LogException(ex);
transaction.Rollback();
}
conn.Close();
}
}
return response;
}
now on response.Ref1 = Convert.ToString(p.Get<int>("#SP_ID")); line in some of my procedure I am getting SP_ID as output parameter and in some I am not getting SP_ID as output parameter
but the problem is when I am not returning SP_ID as output parameter I am getting error of
The given key was not present in the dictionary.
I want to check the key before execution of p.get<int>()
how can I do this?
So I fixed this by myself and thanks to #MarcGravell.
I declared a parameter in my DapperClass where I am using common ExecuteAsync method.
private DynamicParameters _Param;
public DapperClass()
{
_Param = new DynamicParameters();
}
now before transaction.Commit() line I am assigning the value to my parameter _Param = p;
and I created a public method with return type of DynamicParameters like below
public DynamicParameters GetDynamicParameters()
{
return _Param;
}
and also added a code like below from where I am executing my common dapper class
SPResponse response = await _Dapper.ExecuteAsync("[dbo].[TemplateAdd]", _DynamicParameter);
if (response.ReturnStatus == "0")
{
DynamicParameters dp = _Dapper.GetDynamicParameters();
response.Ref1 = Convert.ToString(dp.Get<int>("#SP_ID"));
response.Ref2 = request.FileServerId;
}
I created a generic method in reading sql statement, but I am having a memory leak whenever I do a select query and using while read.
Sample Query:
public CMItemPackagingType GetItemPackagingType(int itemID)
{
try
{
List<CommandParameter> param = new List<CommandParameter>();
StringBuilder sb = new StringBuilder();
using (BaseConnection db = new BaseConnection())
{
sb.Append("SELECT RATIO, PACKAGING_TYPE_CODE FROM ITEM_PACKAGING_TYPE WHERE ROUND_UP = 0.01 AND ITEM_ID = #itemID");
param.Add(new CommandParameter("#itemID", itemID));
using (var rs = db.ExecSQL(sb.ToString(), param.ToArray()))
{
CMItemPackagingType cmItemInfo = new CMItemPackagingType();
while (rs.Read())
{
CMItemPackagingType list = new CMItemPackagingType();
if (!rs.IsDBNull(0))
list.Ratio = Convert.ToInt32(rs.GetValue(0));
if (!rs.IsDBNull(1))
list.PackagingTypeCode = rs.GetValue(1).ToString();
cmItemInfo.ItemPackagingTypeList.Add(list);
}
return cmItemInfo;
}
}
}
catch (Exception ex)
{
GlobalFramework.HandleException(ex);
}
return null;
}
Generic Reader:
public DbDataReader ExecSQL(string sqlStmt, CommandParameter[] param)
{
List<MySqlParameter> p = ParameterMySql(param);
_mySqlConn = new MySqlConnection(szConnect);
if (_mySqlConn.State == ConnectionState.Open)
{
_mySqlConn.Close();
}
_mySqlConn.Open();
_mySqlComm = new MySqlCommand(sqlStmt, _mySqlConn);
_mySqlComm.Parameters.AddRange(p.ToArray());
MySqlDataReader reader = _mySqlComm.ExecuteReader();
return reader;
}
I'm assuming the BaseConnection is a wrapper around a SqlConnection and _mySqlConn is an instance of BaseConnection. I suspect the issue is that you are opening and closing the connection in ExecSQL and at the same time have a using statement around BaseConnection creating this leak. I would refactor your code with proper placement of using statements to ensure correct disposal of the objects and freeing of resources.
Example
var query = "YOUR QUERY";
using (var connection = new SqlConnection("YOUR CONNECTION STRING"))
{
using (var command = new SqlCommand(query, connection))
{
await connection.OpenAsync();
using (var reader = await command.ExecuteReaderAsync())
{
if (reader != null)
{
while (await reader.ReadAsync())
{
// your logic
}
}
} // reader closed and disposed up here
} // command disposed here
} //connection closed and disposed here
}
Also notice how I'm using the async versions of the ADO.NET methods. Async commands are critical in achieving scale, throughput, and latency.
I recommend you use Dapper over trying to develop a generic data reader and writing all the boilerplate ADO.NET code yourself.
I Create A News Site With MVC5 But I Have Problem .
in Model i Create A Repository Folder And in this i Create Rep_Setting for
Connect to Tbl_Setting in DataBase .
public class Rep_Setting
{
DataBase db = new DataBase();
public Tbl_Setting Tools()
{
try
{
var qGetSetting = (from a in db.Tbl_Setting
select a).FirstOrDefault();
return qGetSetting;
}
catch (Exception)
{
return null;
}
}
}
And i Create a Rep_News for Main Page .
DataBase db = new DataBase();
Rep_Setting RSetting = new Rep_Setting();
public List<Tbl_News> GetNews()
{
try
{
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals("News")
select a).OrderByDescending(s => s.ID).Skip(0).Take(RSetting.Tools().CountNewsInPage).ToList();
return qGetNews;
}
catch (Exception ex)
{
return null;
}
}
But This Code Have Error to Me
OrderByDescending(s=>s.ID).Skip(0).Take(RSetting.Tools().CountNewsInPage).ToList();
Error :
Error 18 'System.Linq.IQueryable<NewsSite.Models.Domain.Tbl_News>' does
not contain a definition for 'Take' and the best extension method overload
'System.Linq.Queryable.Take<TSource>(System.Linq.IQueryable<TSource>, int)' has
some invalid arguments
E:\MyProject\NewsSite\NewsSite\Models\Repository\Rep_News.cs 50 52 NewsSite
How i Resolve it ?
Try it this way. The plan of debugging is to split your execution, this also makes for a more reusable method in many cases. And a good idea is to avoid using null and nullables if you can, if you use them "on purpose" the you must have a plan for them.
DataBase db = new DataBase();
Rep_Setting RSetting = new Rep_Setting();
public List<Tbl_News> GetNews()
{
int skip = 0;
Tbl_Setting tools = RSetting.Tools();
if(tools == null){ throw new Exception("Found no rows in the database table Tbl_Setting"); }
int? take = tools.CountNewsInPage;//Nullable
if(!take.HasValue)
{
// Do you want to do something if its null maybe set it to 0 and not null
take = 0;
}
string typeStr = "News";
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals(typeStr)
select a).OrderByDescending(s => s.ID).Skip(skip).Take(take.Value);
return qGetNews.ToList();
}
if qGetNews is a empty list you now don't break everything after trying to iterate on it, like your return null would. instead if returning null for a lit return a new List<>() instead, gives you a more resilient result.
So I said reusable method, its more like a single action. So you work it around to this. Now you have something really reusable.
public List<Tbl_News> GetNews(string typeStr, int take, int skip = 0)
{
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals(typeStr)
select a).OrderByDescending(s => s.ID).Skip(skip).Take(take);
return qGetNews.ToList();
}
Infact you shjould always try to avoid returning null if you can.
public class Rep_Setting
{
DataBase db = new DataBase();
public Tbl_Setting Tools()
{
var qGetSetting = (from a in db.Tbl_Setting
select a).FirstOrDefault();
if(qGetSetting == null){ throw new Exception("Found no rows in the database table Tbl_Setting"); }
return qGetSetting;
}
}
Given a build definition, I extract the following pieces from it:
m_template = (DynamicActivity)WorkflowHelpers.DeserializeWorkflow(buildDefinition.Process.Parameters);
Properties = m_template.Properties.ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
Metadata = WorkflowHelpers.GetCombinedMetadata(m_template).ToDictionary(m => m.ParameterName);
m_parameters = WorkflowHelpers.DeserializeProcessParameters(buildDefinition.ProcessParameters)
Now I wish to know the value of an arbitrary process parameter.
My current code is:
public ParameterValue GetParameterValue(string name)
{
object propValue;
var valueType = GetParameterType(name, out propValue);
object value;
if (!m_parameters.TryGetValue(name, out value))
{
value = propValue;
}
return new ParameterValue(valueType, value);
}
private Type GetParameterType(string name, out object value)
{
value = null;
if (Properties != null)
{
DynamicActivityProperty property;
if (Properties.TryGetValue(name, out property))
{
var inArgument = property.Value as InArgument;
if (inArgument != null)
{
if (inArgument.Expression != null)
{
var exprString = inArgument.Expression.ToString();
if (!exprString.StartsWith(": VisualBasicValue<"))
{
value = exprString;
}
}
return inArgument.ArgumentType;
}
if (property.Value != null)
{
value = property.Value;
return property.Value.GetType();
}
var typeName = property.Type.ToString();
if (typeName.StartsWith(IN_ARGUMENT_TYPE_NAME_PREFIX))
{
typeName = typeName.Substring(IN_ARGUMENT_TYPE_NAME_PREFIX.Length, typeName.Length - IN_ARGUMENT_TYPE_NAME_PREFIX.Length - 1);
return Type.GetType(typeName, true);
}
return property.Type;
}
}
return typeof(string);
}
Unfortunately, this code stumbles for parameters satisfying all of the following conditions:
The parameter value is wrapped as InArgument<T>.
T is a non primitive type, for example string[]
The build definition does not override the value inherited from the process template.
What happens is that:
Because the value is non primitive exprString.StartsWith(": VisualBasicValue<") and I do not know how to handle it. Hence propValue is null.
Because the value is not overridden by the build definition !m_parameters.TryGetValue(name, out value) and hence I just return propValue.
As a result my logic returns null. But it is wrong! For example, I have a string[] parameter which has a list of string in the process template, but my logic returns null for the reasons explained.
So, what is the proper way to compute it?
You can use the following code (included in another link) to get value and type of one process parameter:
TfsTeamProjectCollection tfctc = new TfsTeamProjectCollection(new Uri("http://tfsservername:8080/tfs/DefaultCollection"));
IBuildServer bs = tfctc.GetService<IBuildServer>();
IBuildDetail[] builds = bs.QueryBuilds("teamprojectname", "builddefinitionname");
foreach (var build in builds)
{
var buildefinition = build.BuildDefinition;
IDictionary<String, Object> paramValues = WorkflowHelpers.DeserializeProcessParameters(buildefinition.ProcessParameters);
string processParametersValue = paramValues["argument1"].ToString();
Console.WriteLine(processParametersValue);
}
Also have a check on this case: TFS 2010: Why is it not possible to deserialize a Dictionary<string, object> with XamlWriter.Save when I can use XamlReader for deserializing
This code has been simplified for this example.
The query is actually returned from a service, which is why I would prefer to write the method this way.
[HttpGet]
public PageResult<ExceptionLog> Logging(ODataQueryOptions<ExceptionLog> options)
{
var query = from o in _exceptionLoggingService.entities.ExceptionDatas
select new ExceptionLog {
ExceptionDataId = o.ExceptionDataId,
SiteId = o.SiteId,
ExceptionDateTime = o.ExceptionDateTime,
StatusCode = o.StatusCode,
Url = o.Url,
ExceptionType = o.ExceptionType,
ExceptionMessage = o.ExceptionMessage,
Exception = o.Exception,
RequestData = o.RequestData
};
var results = options.ApplyTo(query) as IEnumerable<ExceptionLog>;
var count = results.LongCount();
return new PageResult<ExceptionLog>(results, Request.GetNextPageLink(), count);
}
The above code errors on "results.LongCount()" with the following Exception:
SqlException: The text, ntext, and image data types cannot be compared or sorted, except when using IS NULL or LIKE operator.
It appears that I'm getting an exception with when trying to page, like this "$top=2". Everything works fine if my querystring is like this "$filter=ExceptionDataId gt 100".
Since ExceptionData (the Entity) matches ExceptionLog (business model) I can do something like this as a workaround:
[HttpGet]
public PageResult<ExceptionLog> Logging(ODataQueryOptions<ExceptionData> options)
{
var query = from o in _exceptionLoggingService.entities.ExceptionDatas
orderby o.ExceptionDateTime descending
select o;
var results = from o in options.ApplyTo(query) as IEnumerable<ExceptionData>
select new ExceptionLog {
ExceptionDataId = o.ExceptionDataId,
SiteId = o.SiteId,
ExceptionDateTime = o.ExceptionDateTime,
StatusCode = o.StatusCode,
Url = o.Url,
ExceptionType = o.ExceptionType,
ExceptionMessage = o.ExceptionMessage,
Exception = o.Exception,
RequestData = o.RequestData
};
return new PageResult<ExceptionLog>(results, Request.GetNextPageLink(), results.LongCount());
}
But this doesn't completely work for me because it's a little hackish and I can't use the service's method which already gives me an IQueryable.
Another thing to note, is if the Logging method is converted to IQueryable, everything works correctly. But I need to return the Count with the query so I have to return a PageResult.
This is the workaround I'm using. I only apply the filter from the ODataQueryOptions and I manually apply the Top and Skip.
First I created some extension methods:
using System;
using System.Collections.Generic;
using System.Linq;
namespace System.Web.Http.OData.Query
{
public static class ODataQuerySettingsExtensions
{
public static IEnumerable<T> ApplyFilter<T>(this IQueryable<T> query, ODataQueryOptions<T> options)
{
if (options.Filter == null)
{
return query;
}
return options.Filter.ApplyTo(query, new ODataQuerySettings()) as IEnumerable<T>;
}
public static IEnumerable<T> ApplyTopAndTake<T>(this IEnumerable<T> query, ODataQueryOptions<T> options)
{
IEnumerable<T> value = query;
if (options.Top != null)
{
value = value.Take(options.Top.Value);
}
if (options.Skip != null)
{
value = value.Skip(options.Skip.Value);
}
return value;
}
}
}
Now my method looks like this:
[HttpGet]
public PageResult<ExceptionLog> Logging(ODataQueryOptions<ExceptionLog> options)
{
// GetLogs returns an IQueryable<ExceptionLog> as seen in Question above.
var query = _exceptionLoggingService.GetLogs()
.ApplyFilter(options);
var count = query.Count();
var results = query.ApplyTopAndTake(options);
return new PageResult<ExceptionLog>(results, Request.GetNextPageLink(), count);
}