Working with graphson result in Cosmos DB - c#

I am working with the result of cosmos db query by passing to constructor of a class:
public Session GetASession()
{
IDocumentQuery<dynamic> query = database.Client.CreateGremlinQuery<dynamic>(database.Graph, $"g.V()");
var session = new Data(query.ExecuteNextAsync().Result.FirstOrDefault());
return session;
}
Which Session class is implemented likes the following:
public Class Session
{
dynamic graphson;
public Session(dynamic graphson)
{
this.graphson = graphson;
}
public string Id
{
get
{
return (string)graphson.id;
}
set
{
graphson.id = value;
}
}
}
The issue is when calling GetASession function, although the query get some session from db, but Id in returned session in not available and get error in this way. Hence, the question is where is the problem?

As I found returned object from the query is weak reference object, so if we not assign it to a variable, it will be disposed. Hence, the solution is:
public Session GetASession()
{
IDocumentQuery<dynamic> query = database.Client.CreateGremlinQuery<dynamic>(database.Graph, $"g.V()");
var result = query.ExecuteNextAsync().Result.FirstOrDefault();
var session = new Data(result); // this solves the problem
return session;
}

Related

Php to C# aspnet mvc

i have transform a php/js code to js/c#, but i stuck for update the new value.
The php code is :
`if (isset($_POST['update'])) {
foreach($_POST['positions'] as $position) {
$index = $position[0];
$newPosition = $position[1];
$conn->query("UPDATE country SET position = '$newPosition' WHERE id='$index'");
}
exit('success');
}`
My "empty" c# code
[HttpPost]
public ActionResult Index (userTable index)
{
picturesEntities MyDb = new picturesEntities();
homeViewModel HVM = new homeViewModel();
HVM.userTables = MyDb.userTables.ToList();
if (Request["update"] != null)
{
foreach (Request["positions"])
{
MyDb.SaveChanges();
}
return View(HVM);
}
}
If someone could help me for it that would be great, i'm stuck on it for days and i didn't find a workning solution yet.
Thanks to everyone who read my message.
Most ASP.NET will bind a custom class which will be compatible to your request.
public class UserPositionsRequest
{
public bool Update { get; set; }
// For orderly, this actually be a list of a custom class
public List<int[]> Positions { get; set; }
}
This by any means is not a complete and working solution, the following code was never been tested and can be consider as pseudo-like code.
Also, the .Id and .Position should be the same sensitivity as in Db.
// Binding our UserPositionsRequest class
public void Index(UserPositionsRequest request) {
// Checking if we should update, if you will change the request to boolean type: "true"
// ..on the client side, then you could actually change the condition to be: if (request.Update)
if (request.Update == 1) {
// Creating database connection using (I assume) EntityFramework
using (var picturesEntities = new picturesEntities()) {
// Building a dictionary for fast lookup. Key, Value as the 0, 1 arg respectfully
var usersDataToUpdate = request.Positions.ToDictionary(p => p[0], p => p[1]);
// Finding the entries that needs to be updated
var usersEntitiesToUpdate = picturesEntities.userTables.Where(cntry => usersDataToUpdate.ContainsKey(cntry.Id));
// Iterating over the entities
foreach (var userEntity in usersEntitiesToUpdate) {
// Updating their position.
userEntity.Position = usersDataToUpdate[userEntity.Id];
}
picturesEntities.SaveChanges();
}
}
// Probably you wanted to return something here, but it's probably an ajax and you can skip that.
}

How do I cache lookup data with Entity Framework 6

I'm learning my way around EF, and I know caching is faster than a round trip to the DB for things like state, country, etc. But I'm not sure how to implement it. I was looking at this post (entities from local cache) that mentioned an extension, but is there something built in I should leverage?
I'd like to have a function like this that wouldn't have to go to the db every time:
public static int GetCountryId(string countryCode = "US")
{
if (countryCode == string.Empty)
countryCode = "US"; // Assume US
return db.Country.Where
(
p => p.CountryCode == countryCode
).Select(p => p.CountryId).First();
}
Updated:
I'm now thinking about a GetCached function that would use generics to hold some lookup lists in memory. Somthing like this:
public class Lookups
{
private static MkpContext db = new MkpContext();
public static IEnumerable GetCached(CachedLists list)
{
ObjectCache cache = MemoryCache.Default;
var listOut = cache[list.ToString()] as IEnumerable;
if (listOut != null) return listOut;
switch (list)
{
case CachedLists.Countries:
cache.Set
(
list.ToString(),
db.Country.ToList(),
new DateTimeOffset(DateTime.Now,new TimeSpan(1,0,0,0))
);
break;
default:
return null;
}
listOut = cache[list.ToString()] as IEnumerable;
return listOut;
}
}
public enum CachedLists
{
Countries,
}
But the above solution would leave me with an un-typed Enumerable. I'd love to be able to specify the types somehow, or better yet, do some sort of extension.
There are a lot of options, but here's one approach that will work well if users are mostly querying the same few country codes:
Create a MemoryCache instance to use as a static, private, readonly field on your class. In your method, try to get a cached item from this cache if there is one with the given countryCode as its key. If it's not there, do your database query and Add the result into the cache before returning it.
By the way, the approach in the article you linked probably isn't a very good approach: it will only help if you've already got data in the specific database context instance that you're dealing with, and usually it's best for your contexts to be short-lived. It's also really CPU-intensive to compile an expression into a function, and then run that function against every entity that the context has cached, just to find out whether the item is there or not. If you then find out that it's not there, and you have to go back to the database anyway, you just wasted time and resources.
The method you have proposed is usually what I do to return cached data.
However data is cached as an object and therefor you have to return it as the object you expect.
Lets assume that your country class is represented by:
public class Country
{
#region Constructors
public Country(string code, string name)
{
this.Code = code;
this.Name = name;
}
#endregion
#region Properties
public string Name { get; set; }
public string Code { get; set; }
#endregion
}
What we need to do is look up our cache by a given key, if exists return the cache, otherwise get from database - same logic as you did.
Difference is here var listOut = cache[list.ToString()] as IEnumerable;
You want to check whether the value for that key is of type Country
If we define a GetCache method as following:
static object GetCache(string cacheKey)
{
if (Cache[cacheKey] is object cachedResult)
{
return cachedResult;
}
return null;
}
What we need to do in order to return a List<Country> is
if (GetCache(cacheKey) is List<Country> cachedData)
{
return cachedData;
}
Now instead of a list of object we have a List<Country>
I have made a simple console app to show the result - hope it helps:
namespace ConsoleApp3
{
#region Usings
using System;
using System.Collections.Generic;
using System.Runtime.Caching;
#endregion
class Program
{
#region Fields
private static readonly ObjectCache Cache = MemoryCache.Default;
#endregion
static void Main(string[] args)
{
//simulates app life span
for (int i = 0; i < 5; i++)
{
var countries = GetData();
foreach (var country in countries)
{
Console.WriteLine(country.Name);
}
Console.ReadLine();
}
}
static List<Country> GetData()
{
string cacheKey = "Country-Lookup";
if (GetCache(cacheKey) is List<Country> cachedData)
{
return cachedData;
}
// otherwise do some logic stuff and get from DB
//db data simulation
List<Country> coutries = new List<Country>
{
new Country("IT", "Italy"),
new Country("UK", "United Kindom"),
new Country("US", "United States")
};
//add to cache
AddToCache(cacheKey, coutries);
return coutries;
}
static object GetCache(string cacheKey)
{
if (Cache[cacheKey] is object cachedResult)
{
return cachedResult;
}
return null;
}
static void AddToCache(string cacheKey, object dataToCache)
{
if (dataToCache == null)
{
return;
}
Cache.Set(cacheKey, dataToCache, DateTimeOffset.Now.AddMinutes(1));
}
}
}
You can use EntityFramework Plus.
public static int GetCountryId(string countryCode = "US")
{
return db.Country.Where
(
p => p.CountryCode == countryCode
).Select(p => p.CountryId).First();
}
Would probably become...
public static int GetCountryId(string countryCode = "US")
{
using var context = new Context();
var allCountries = context.Country
.FromCache({cachePolicy})
.ToDictionary(x => x.CountryCode);
return allCountries[countryCode];
}
For something basic like mapping a country code to a countryId I'd suggest keeping it simple and using a dictionary. If this is happening inside a web application you'll want to use a ConcurrentDictionary to handle multiple threads hitting the code, otherwise a normal dictionary will be fine.
You could also have some code that populates the dictionary when the app starts up to make the experience even snappier for users.
static ConcurrentDictionary<string, int> countryLookup = new ConcurrentDictionary<string, int>();
public static int GetCountryId(string countryCode = "US")
{
if (countryCode == string.Empty)
countryCode = "US"; // Assume US
if (countryLookup.TryGetValue(countryCode, out int countryId))
return countryId;
var countryId = db.Country
.First(p => p.CountryCode == countryCode)
.CountryId;
countryLookup.TryAdd(countryCode, countryId);
return countryId;
}

storing Linq To Entities query in new object projection

I have a Linq to Entities query and I want to select some specific columns and store the new object into a pre-defined object. However, I'm getting the error
<object> does not contain a constructor that takes 0 arguments.
Not sure what is wrong here...
Also not sure if this is the best way or if using anonymous type is better instead of creating a payroll object.
Linq Query
public Payroll GetTestCasePayroll(decimal testScenarioID) //not sure if object is correct return
{
Payroll instance = (from o in DbContext.UI_OnDemandCheckHeader
where o.TestScenarioID == testScenarioID
select new Payroll(o.PayEntityCode, o.PayrollYear, o.PayrollNumber)).First();
//{ PayEntityCode = , PayrollYear = o.PayrollYear, PayrollNumber = o.PayrollNumber }).First();
return instance;
}
Payroll object
class Payroll
{
private string _payEntityCode;
private decimal _payrollYear;
private string _payrollNumber;
public Payroll(string payEntityCode, decimal payrollYear, string payrollNumber)
{
PayEntityCode = payEntityCode;
PayrollYear = payrollYear;
PayrollNumber = payrollNumber;
}
public decimal PayrollYear
{
get { return _payrollYear; }
set { _payrollYear = value; }
}
public string PayEntityCode
{
get { return _payEntityCode; }
set { _payEntityCode = value; }
}
public string PayrollNumber
{
get { return _payrollNumber; }
set { _payrollNumber = value; }
}
Your Payroll class needs a constructor that takes no parameters e.g.
Public Payroll() { }
Linq works by creating an empty instance of the output class and then using the setters on each of the properties. It does not use anything but an empty constructor.

Better way to manage Session data

I need to persist in Session some data.
I wrote many properties like that:
public List<string> FillOrder
{
get { return Session[SessionKeys.QueryFillOrder] as List<string> ?? new List<string>(); }
set { Session[SessionKeys.QueryFillOrder] = value; }
}
When I have to consume this data I have to write code like that:
List<string> fillOrder = FillOrder;
fillOrder.Add(accordion.ID);
FillOrder = fillOrder;
that seems to me so ugly, because I would prefer to do that:
FillOrder.Add(accordion.ID);
but this way my value would not be saved back in Session.
Can you think of any better way to achieve the same result?
Thank you very much!
I always use a wrapper class around the ASP.NET session to simplify access to session variables:
public class MySession
{
// private constructor
private MySession()
{
FillOrder = new List<string>();
}
// Gets the current session.
public static MySession Current
{
get
{
var session = (MySession)HttpContext.Current.Session["__MySession__"];
if (session == null)
{
session = new MySession();
HttpContext.Current.Session["__MySession__"] = session;
}
return session;
}
}
// **** add your session properties here, e.g like this:
public List<string> FillOrder {get; set; }
public string Property1 { get; set; }
public DateTime MyDate { get; set; }
public int LoginId { get; set; }
}
This class stores one instance of itself in the ASP.NET session and allows you to access your session properties in a type-safe way from any class, e.g like this:
MySession.Current.FillOrder.Add(accordion.ID);
int loginId = MySession.Current.LoginId;
string property1 = MySession.Current.Property1;
MySession.Current.Property1 = newValue;
DateTime myDate = MySession.Current.MyDate;
MySession.Current.MyDate = DateTime.Now;
This approach has several advantages:
you can initialize your session variables in the constructor (i.e. new List<string>)
it saves you from a lot of type-casting
you don't have to use hard-coded session keys throughout your application (e.g. Session["loginId"]
you can document your session items by adding XML doc comments on the properties of MySession
You can use an extension method as well, but I do think the example by M4N might be better:
EDIT made it a generic type
public static class Extensions
{
public static void AddWithSession<T>(this List<T> list, T value, string key)
{
list.Add(value);
HttpContext.Current.Session[key] = list;
}
}
str.AddWithSession(accordion.ID,SessionKeys.QueryFillOrder);
You could write an own class that implements ICollection or IList, there you would implement Add as Session[...] = ...
Using a single class for all Session variables as suggested by #M4N is a good idea, though it risks becoming a "God" class (in which case you could partition into several classes implemented in this way).
However you could just change your property implemetation as follows:
public List<string> FillOrder
{
get
{
List<string> result = Session[SessionKeys.QueryFillOrder] as List<string>;
if (result == null)
{
result = new List<string>();
Session[SessionKeys.QueryFillOrder] = result;
}
return result;
}
set { Session[SessionKeys.QueryFillOrder] = value; }
}
In this example, you probably don't want a setter.

Error when using WCF dataservice

I'm following this guide and I am getting an error. Can anyone help me?
The code for my datamodel is below
namespace Datalayer {
public class DataModel {
public DataModel()
{
using (btWholesaleDataContext db = new btWholesaleDataContext()) {
//! requires auth
var MACRequestList = from r in db.btRequests
select new Models.BT.Request {
ID = r.ID,
Date = r.DateTime,
StatusCode = 3,
Status = r.Status
};
MACRequests = MACRequestList.AsQueryable();
}
}
public IQueryable<Models.BT.Request> MACRequests { get; private set; }
}
}
The web service gives the error
Cannot access a disposed
object.Object name: 'DataContext
accessed after Dispose.'
When I access MACRequests
I have only posted the code I think is broken. If you want to see more just let me know.
Your data context is being disposed at the end of your constructor, at the end of the using { } block. However when you use the IQueryable MACRequests property, it needs that underlying context, which has since been disposed.
One possible way to handle this is to make your class IDisposable and dispose the context that way:
public class DataModel : IDisposable {
private btWholesaleDataContext wholesaleDataContext;
public DataModel()
{
wholesaleDataContext = new btWholesaleDataContext();
//! requires auth
var MACRequestList = ... ;
MACRequests = MACRequestList.AsQueryable();
}
public IQueryable<Models.BT.Request> MACRequests { get; private set; }
public void Dispose() {
if(wholesaleDataContext != null)
wholesaleDataContext.Dispose();
}
}
Then you have to make sure that DataModel is properly disposed by whatever uses it.
Another alternative is to make MACRequests the actual list of items instead of the IQueryable:
public class DataModel {
public DataModel()
{
using (btWholesaleDataContext db = new btWholesaleDataContext()) {
//! requires auth
var MACRequestList = ... ;
MACRequests = MACRequestList.ToList(); // ToList reads the records now, instead of later.
}
}
public List<Models.BT.Request> MACRequests { get; private set; }
}
I think its because you are using an IQueryable<>. Its lazily queries the service.
Use List<> instead so that it queries immediately
Or make "btWholesaleDataContext db" into a member variable
Queries to MACRequests are deferred - once you're out of the using block and your DataContext is disposed you're not going to be able to make the query you want.
You're creating the data context in a using block in the constructor of your DataModel...so by the time you access the MACRequests, the data context has been disposed.
Consider the following:
public class DataModel : IDisposable {
btWholesaleDataContext db = new btWholesaleDataContext();
public void Dispose()
{
btWholesaleDataContext.Dipose();
}
public IQueryable<Models.BT.Request> MACRequests {
get {
return from r in db.btRequests
select new Models.BT.Request {
ID = r.ID,
Date = r.DateTime,
StatusCode = 3,
Status = r.Status
};
}
}
}
Note that this usage will work:
using (var dm = new DataModel())
{
dm.MACRequests.ToArray();
}
but this will fail for the same reason as the original:
IQueryable<Models.BT.Request> requests = null;
using (var dm = new DataModel())
{
requests = dm.MACRequests;
}
// this will fail because the context is disposed by the time we force enumeration of the query
requests.ToArray();
...Alternatively, since WCF data services can't filter on projections, and thus all you can really do with the query
from r in db.btRequests
select new Models.BT.Request {
ID = r.ID,
Date = r.DateTime,
StatusCode = 3,
Status = r.Status
};
is execute it...
just consider changing your original code to return an array or a list instead of leaving it as a queryable.

Categories

Resources