spring data redis use #RedisHash to generate hash then retrieve its fields - spring-data-redis

friends! I want to retrieve only a field of a hash from redis database using spring RedisTemplate, but it does not work. Because I think it is reasonable to do it since #RedisHash makes the object a hash table in Redis, I have tried to retrieve or update part of the hash, but don't know why it does not work:
This is the entity I use:
#Data
#RedisHash("arithmetic_gamestats")
public class GameStats {
/**
* Used for redis serialization
*/
public GameStats() {}
public GameStats(long userId, int score) {
this.userId = userId;
this.score = score;
}
public GameStats(long userId, int score, List<Badge> badges) {
this.userId = userId;
this.score = score;
this.badges = badges;
}
#Id
private Long userId;
private int score;
private List<Badge> badg/es;
}
// this is my test, first I create a new object, and save it to redis, this works totally fine:
//#Test #Order(5)
public void testRedisHashtable() {
long userId = userIds.get(random.nextInt(0, userIds.size()));
GameStats gameStats = new GameStats(userId, 1000);
GameStats dbGameStats = gamestatsRepository.save(gameStats);
assertThat(dbGameStats).isNotNull();
}
After insert one instance of the GameStats class in the test method, I get the following result in Redis server which is what I expected:
127.0.0.1:6379> keys *
1) "arithmetic_gamestats"
2) "arithmetic_gamestats:-5461129489864155017"
127.0.0.1:6379> type "arithmetic_gamestats"
set
127.0.0.1:6379> type "arithmetic_gamestats:-5461129489864155017"
hash
127.0.0.1:6379> smembers "arithmetic_gamestats"
1) "-5461129489864155017"
127.0.0.1:6379> hgetall "arithmetic_gamestats:-5461129489864155017"
1) "_class"
2) "com.worldexplorer.arithmeticgamification.entity.GameStats"
3) "score"
4) "1000"
5) "userId"
6) "-5461129489864155017"
127.0.0.1:6379> hget "arithmetic_gamestats:-5461129489864155017" "score"
"1000"
I copy the key from redis to retrieve the data, but the result is null, or empty:
#Test #Order(6)
public void testRedisHash() {
String key = "arithmetic_gamestats:-5461129489864155017";
Object scoreObject = redisTemplate.opsForHash().get(key, "score");
System.out.println("score = " + scoreObject);
Set<Object> keySet = redisTemplate.opsForHash().keys(key);
for (Object object : keySet) {
System.out.println("key = " + object);
}
Map<Object, Object> keyvalueMap = redisTemplate.opsForHash().entries(key);
for (Map.Entry<Object, Object> entry : keyvalueMap.entrySet()) {
System.out.println("key-value = " + entry.getKey() + "-" + entry.getValue());
}
System.out.println("keySet = " + keySet);
System.out.println("keyvalueMap = " + keyvalueMap);
}
This is the result printed in the console:
score = null
keySet = []
keyvalueMap = {}
And here is the repository:
public interface GamestatsRepository extends CrudRepository<GameStats, Long>{
}

Related

Creating a unique string for request records ASP.NET Core MVC

I have a request table that requires a unique string Id to be displayed for the users.
After some searches I found Kevin's post that perfectly worked for me.
here
But when the request started to have an id of 4 digit (ex. 5041), I get an IndexOutOfRangeException error. How is that possible? And how can I fix it?
private static Random random = new Random();
private static int largeCoprimeNumber = 502277;
private static int largestPossibleValue = 1679616;
private static char[] Base36Alphabet = new char[] { '0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
public static string GetTicket(int id)
{
int adjustedID = id * largeCoprimeNumber % largestPossibleValue;
string ticket = IntToString(adjustedID);
while (ticket.Length < 4)
ticket = "0" + ticket;
return ticket + new string(Enumerable.Repeat(Base36Alphabet, 6).Select(s => s[random.Next(s.Length)]).ToArray());
}
private static string IntToString(int value)
{
string result = string.Empty;
int targetBase = Base36Alphabet.Length;
do
{
result = Base36Alphabet[value % targetBase] + result;
value = value / targetBase;
}
while (value > 0);
return result;
}
Calling the GetTicket method:
Request request = new Request()
{
//properties
};
_db.Request.Add(request);
await _db.SaveChangesAsync();
request.TicketId = GetTicket(request.Id);
The answer is: when you multiply the answer is larger than the int.Max - that causes the number to be a negative. The solution is to change the type to long.
Here is tested code:
private static Random random = new Random();
private static long largeCoprimeNumber = 502277;
private static long largestPossibleValue = 1679616;
private static char[] Base36Alphabet = new char[] { '0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
public static string GetTicket(long id)
{
long adjustedID = (id * largeCoprimeNumber) % largestPossibleValue;
string ticket = LongToString(adjustedID);
while (ticket.Length < 4) ticket = "0" + ticket;
return ticket + new string(Enumerable.Repeat(Base36Alphabet, 6).Select(s => s[random.Next(s.Length)]).ToArray());
}
private static string IntToString(int value)
{
string result = string.Empty;
int targetBase = Base36Alphabet.Length;
do
{
result = Base36Alphabet[value % targetBase] + result;
value = value / targetBase;
}
while (value > 0);
return result;
}
private static string LongToString(long value)
{
string result = string.Empty;
int targetBase = Base36Alphabet.Length;
do
{
result = Base36Alphabet[value % targetBase] + result;
value = value / targetBase;
}
while (value > 0);
return result;
}

Xamarin.Forms SQLite ,initialize data once on table creation

I am new in xamarin and I am trying to make xamarin.form app which contains sqlite database. So I know that the table is created once but also I have some records that I need to be in that table by default. I mean when table is created the data also must be initialized with it once. According to tutorial I have a class to handle the database called DataAccess.cs
class DataAccess : IDisposable
{
public void Dispose()
{
database.Dispose();
}
private SQLiteConnection database;
public ObservableCollection<DataModel> dataz { get; set; }
private static object collisionLock = new object();
public DataAccess()
{
database = DependencyService.Get<IConfig>().DbConnection();
database.CreateTable<DataModel>();
//database.Insert(new DataModel { Did = 1 , Data = "aaaa"});
//database.Insert(new DataModel { Did = 2, Data = "bbb" });
//database.Insert(new DataModel { Did = 3, Data = "ccc" });
this.dataz = new ObservableCollection<DataModel>(database.Table<DataModel>());
if (!database.Table<DataModel>().Any())
{
addNewData();
}
}
public void addNewData()
{
this.dataz.Add(new DataModel { Did = 1, Data = "aa" });
}
public void SaveData(DataModel record)
{
lock (collisionLock)
{
database.Insert(record);
}
}
public DataModel GetDataById(int id)
{
lock (collisionLock)
{
return database.Table<DataModel>().
FirstOrDefault(x => x.Did == id);
}
}
public List<DataModel> GeyAllData()
{
return database.Table<DataModel>().ToList();
}
}
Since the table is created in above class instructor. So I tried to initialized data there but data added to table on each run. So I confused how to initialize data on first run only.
You could go one of two ways.
1: Check if the table does not exist yet and if not, create it and add your data
var result = await conn.ExecuteScalarAsync<int>("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='DataModel';", new string[] { });
if (result == 0)
{
await conn.CreateTableAsync<DataModel>();
// Insert your initial data
}
2: Always check if the data exists and insert it if it does not
FYI: Assuming Did is your PrimaryKey of DataModel
var row = await conn.FindAsync<Record>(1);
if (row == null)
{
// Insert the "Did = 1" row
}

How do I create a dynamic Linq query to fill an ASP.NET databound ListView?

I am having some trouble figuring out the right way to go about creating a dynamic query that I can use values from DropDownList controls to filter and sort/order the results of a database query to fill a ListView. I am able to hard code individual queries, which works ok, except for the fact that it takes an incredible amount of effort, and is not easily changed.
My code is as follows (using all filters):
queryResult = From product In myEntities.InventoryProducts
Where product.VendorID = ddlFilterVendor.SelectedValue And product.ItemType = ddlItemType.SelectedValue And product.LabelSize = ddlLabelSize.SelectedValue And product.PrintLabel = boolPrint And product.Edited = boolEdited
Order By product.ID Ascending
Select product
Return queryResult
Is there a better method to this? I would like to be able to select the value from each DropDownList and generate a custom WHERE clause, as well as an ORDER BY clause.
Any help would be greatly appreciated, thanks.
I can give you a simple example as to how to to proceed with your idea. I am sure if you look through StackOverflow or search via google you will get code that does a better job of dynamic expression building. The same concept can be used for order by.
void Main()
{
var ops = new List<Ops>
{
new Ops
{
OperandType = typeof(string),
OpType=OpType.Equals,
OperandName = "Name",
ValueToCompare = "MM" // in your case this will be the values from the dropdowns
},
new Ops
{
OperandType = typeof(int),
OpType=OpType.Equals,
OperandName = "ID",
ValueToCompare = 1
},
};
var testClasses = new List<TestClass>
{
new TestClass { ID =1, Name = "MM", Date = new DateTime(2014,12,1)},
new TestClass { ID =2, Name = "BB", Date = new DateTime(2014,12,2)}
};
// this will produce prop => ((prop.Name == "MM") And (prop.ID == 1))
var whereDelegate = ExpressionBuilder.BuildExpressions<TestClass>(ops);
foreach(var item in testClasses.Where(whereDelegate))
{
Console.WriteLine("ID " +item.ID);
Console.WriteLine("Name " +item.Name);
Console.WriteLine("Date" + item.Date);
}
}
// Define other methods and classes here
public enum OpType
{
Equals
}
public class Ops
{
public Type OperandType {get; set;}
public OpType OpType {get; set;}
public string OperandName {get;set;}
public object ValueToCompare {get;set;}
}
public class TestClass
{
public int ID {get;set;}
public string Name {get; set;}
public DateTime Date {get;set;}
}
public class ExpressionBuilder
{
public static Func<T,bool> BuildExpressions<T>( List<Ops> opList)
{
Expression currentExpression= null;
var parameterExpression = Expression.Parameter(typeof(T), "prop");
for(int i =0; i< opList.Count; i++)
{
var op = opList[i];
Expression innerExpression = null;
switch(op.OpType)
{
case OpType.Equals :
{
var propertyExpression = Expression.Property(parameterExpression ,
op.OperandName);
var constExpression = Expression.Constant(op.ValueToCompare);
innerExpression = Expression.Equal(propertyExpression,
constExpression);
break;
}
}
if (i >0)
{
currentExpression = Expression.And(currentExpression, innerExpression);
}
else
{
currentExpression = innerExpression;
}
}
var lambdaExpression = Expression.Lambda<Func<T,bool>>(currentExpression,
new []{parameterExpression });
Console.WriteLine(lambdaExpression);
return lambdaExpression.Compile() ;
}
}

C# Error: Cannot read from a Closed reader...?

I have this code below. Gets data and sets data property to the values gathered.
public struct TrblShootData
{
public List<string> Logins;
public IEnumerable<Hieracrhy> Hierarchy;
public IEnumerable<EmployeeTeam> EmpTeam;
}
public TrblShootData TroubleShootData
{
get;
private set;
}
class DataGetter
{
public void GetData(string FirstName, string LastName, string Login, string Email, bool isFirstName, bool isLastName, bool isLogin, bool isEmail)
{
List<string> logins = null;
IEnumerable<Hieracrhy> hier = null;
IEnumerable<EmployeeTeam> tmemp = null;
TrblShootData tsData = new TrblShootData();
queries q = BuildQuery(FirstName, LastName, Login, Email, isFirstName, isLastName, isLogin, isEmail);
if (q.isValidQueries)
{
DataContext1 mscDB = new DataContext1 ();
using (DataContext2 opsDB = new DataContext2 ())
{
tmemp = opsDB.ExecuteQuery<EmployeeTeam>(q.qryEmployeeTeam);
}
using (DataContext3 rptDB = new DataContext3 ())
{
hier = rptDB.ExecuteQuery<Hieracrhy>(q.qryHierarchy);
if (hier != null)
{
logins = hier.Select(s => s.SalesRepLogin).Distinct().ToList();
}
}
tsData.EmpTeam = tmemp.Select(r=>r);
tsData.Hierarchy = hier.Select(r => r);
tsData.Logins = logins.Select(r => r).ToList();
TroubleShootData = tsData;
}//if
}
}
From another class I attempt to do this:
tshtr.GetData(txtFirstName.Text, txtLastName.Text, txtLogin.Text, txtEmail.Text, chkFirstName.Checked, chkLastName.Checked, chkLogin.Checked, chkEmail.Checked);
gvEmpTeams.DataSource = tshtr.TroubleShootData.EmpTeam;
gvHierarchy.DataSource = tshtr.TroubleShootData.Hierarchy;
gvEmpTeams.DataBind();
gvHierarchy.DataBind();
But at the DataBind() I get an error saying that I cannot read from a closed reader.
I'm not seeing why it would throw this error when I've set my property as above after I've assigned the values in the usings. So I'm not seeing how this is trying to use a closed reader.
Thanks for any help!
Because of deferred execution, your query only executes when the data-binding engine enumerates its results, after you close the DataContext.
You need to call .ToList() before closing the DataContext to force it to be evaluated immediately.

How use custom class in WebMatrix v2?

I do first steps in the ASP.NET and I've a issue with classes. I would like to create a new custom class to support sessions and collect information about the number of users on my website.
I've created a class in file MySession.cs, which has been put in the dir called "App_data" by WebMatrix.
When I try to use this class in .cshtml file, it throws me information it couldn't found that class.
I found in the Web, the class should be placed in App_Code, so I've done it. However, in this moment it shows me an error that classes like "Request" couldn't been found.
How to use custom class in WebMatrix?
My c# code from .cshtml file looks like:
#{
MySession session = new MySession(60);
session.start();
var db = Database.Open("studia");
var data = db.Query("SELECT COUNT(*) as total FROM sessions");
}
and class file looks like:
using System;
using System.Collections.Generic;
using System.Web;
using System.Security.Cryptography;
using System.Data;
using System.Data.SqlClient;
/// <summary>
/// Summary description for sesss
/// </summary>
public class MySession
{
private String _session_id;
private int _session_time;
public MySession(int session_time = 60)
{
_session_time = session_time;
using (MD5 md5Hash = MD5.Create())
{
_session_id = (Request.Cookies["session_id"] != null) ? Server.HtmlEncode(Request.Cookies["sesion_id"].Value) : GetMd5Hash(md5Hash, DateTime.Now);
}
cleanup();
}
public bool isLogged()
{
if (Request.Cookies["session_id"] != null)
{
return true;
}
return false;
}
public void start(string username)
{
DateTime now = DateTime.Now;
var db = Database.Open("studia");
if (isLogged())
{
db.Query("UPDATE sessions SET start_time = " + now + " WHERE session_id = " + _session_id);
}
else
{
db.Query("INSERT INTO sessions (id, start_time, username) VALUES ('" + _session_id + "', '" + now + "', '" + username + "'");
}
HttpCookie session_cookie = new HttpCookie("session_id");
session_cookie.Value = DateTime.Now;
session_cookie.Expires = DateTime.Now.AddSeconds(_session_time);
Response.Cookies.Add(aCookie);
}
public void cleanup()
{
var db = Database.Open("studia");
db.Query("DELETE FROM sessions WHERE start_time < " + (DateTime.Now - _session_time));
}
static string GetMd5Hash(MD5 md5Hash, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
// Verify a hash against a string.
static bool VerifyMd5Hash(MD5 md5Hash, string input, string hash)
{
// Hash the input.
string hashOfInput = GetMd5Hash(md5Hash, input);
// Create a StringComparer an compare the hashes.
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
if (0 == comparer.Compare(hashOfInput, hash))
{
return true;
}
else
{
return false;
}
}
}
If you want to refer to the Request object in a class (as opposed to from within a page file) you need to use HttpContext.Current e.g.
public bool isLogged()
{
return HttpContext.Current.Request.Cookies["session_id"] != null;
}

Resources