Getting items and count with ServiceStack.Redis IRedisTypedClient - servicestack.redis

I'm just starting to work with ServiceStack.Redis. I can put individual key/values into the cache and get them from the cache. However, I can't seem to get all items or a count of the items in the cache.
Here's the code
using (RedisClient cacheClient = new RedisClient(cacheServer))
{
IRedisTypedClient<CustomerEntity> customerCache = cacheClient.As<CustomerEntity>();
customer = bl.FetchCustomer(customerId);
//cache for two minutes
customerCache.SetEntry(customerId, customer, new TimeSpan(0, 2, 0));
//These all show the count as 0
logger.Debug(customerCache.GetAll().Count);
logger.Debug(cacheClient.GetAll<CustomerEntity>().Count);
var customers = customerCache.GetAll();
logger.Debug("{0} customers in the cache", customers.Count);
}

In your CustomerEntity class:
(e.g)
public string strManufacturer;
should be replaced as
public string strManufacturer { get; set; }
I guess redis can't access when the getter and the setter is not explicitly defined.
I was unable to store my C# objects in redis, this modification fixed the issue for me.
I was getting output
"{}"
in redis-cli when I "get" the key before making this modification and GetAll().Count was returning 0 as in your situation.
You should also pay attention of license terms of ServiceStack.Redis if you're going to use it in a production environment. See here for the discussion on SO.

Related

Getting JsonSerializationException

I'm having an issue trying to convert an object to json. The error is a Newtonsoft.Json.JsonSerializationException:
Self referencing loop detected for property 'Project' with type 'System.Data.Entity.DynamicProxies.Project_F29F70EF89942F6344C5B0A3A7910EF55268857CD0ECC4A484776B2F4394EF79'. Path '[0].Categories[0]'.
The problem is that the object (it's actually a list of objects) has a property which is another object that refers back to the first object:
public partial class Project
{
...
public virtual ICollection<Category> Categories { get; set; }
...
}
public partial class Category
{
...
public virtual Project Project { get; set; }
...
}
This is all fine and dandy as far as Entity Framework is concerned, but to convert this to json would result in an infinite regress, hence the exception.
Here is my code:
public async Task<HttpResponseMessage> GetProjects()
{
var projects = _projectService.GetProjects().ToList();
string jsonString = JsonConvert.SerializeObject(projects); // <-- Offending line
return Request.CreateResponse(HttpStatusCode.OK, jsonString);
}
I've looked online for solutions to this and I found this stackoverflow post:
JSON.NET Error Self referencing loop detected for type
They suggest three solutions, none of which work:
1) Ignore the circular reference:
public async Task<HttpResponseMessage> GetProjects()
{
var projects = _projectService.GetProjects().ToList();
JsonSerializerSettings settings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string jsonString = JsonConvert.SerializeObject(projects, settings);
return Request.CreateResponse(HttpStatusCode.OK, jsonString);
}
This resulted in the call to SerializeObject(...) hanging for a bit then throwing a System.OutOfMemoryException (which tells me the circular references were NOT being ignored).
Mind you, the author of this proposed solution at stackoverflow says to set the ignore setting in WebApiConfig.cs but I tried that and it has no effect.
He also says:
"If you want to use this fix in a non-api ASP.NET project, you can add the above line to Global.asax.cs, but first add: var config = GlobalConfiguration.Configuration;"
Mine's a web API with no global file so I shouldn't have to do this.
I also don't want to ignore circular references because I don't want to lose data.
2) Preserve the circular reference:
public async Task<HttpResponseMessage> GetProjects()
{
var projects = _projectService.GetProjects().ToList();
JsonSerializerSettings settings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
};
string jsonString = JsonConvert.SerializeObject(projects, settings);
return Request.CreateResponse(HttpStatusCode.OK, jsonString);
}
This just resulted in the request timing out because it would just hang.
Again, the author says to put this in WebApiConfig.cs, but again this had no effect.
3) Add ignore/preserve reference attributes to the objects and properties:
Ignoring Categories:
public partial class Project
{
...
[JsonIgnore]
public virtual ICollection<Category> Categories { get; set; }
...
}
This has no effect. I hover over the project list and see that it still has categories, and each category still has an instance of the project. I still get the same exception.
Again, even if this worked, I don't want to ignore the categories.
Preserve Categories:
[JsonObject(IsReference = true)]
public partial class Project
{
...
public virtual ICollection<Category> Categories { get; set; }
...
}
Again, same results.
Even if this method worked, the attributes wouldn't be preserved. I'd be doing it on Entity Framework classes which are re-generated automatically every time I recompile. (Is there a way to tell it to set these attributes in the model? Can I set them on the other half of the partial class?)
Alternatively, I'm open to suggestions other than converting to json and sending back in the response. Is there another way to get the data back to the client?
What would be the fix to this problem? Thanks.
Briefly
The best way to fix this problem is to create completely brand-new Models (xxxModel, xxxViewModel, xxxResponse, etc..) on Presentation layer which will be returned to end-users. Than just cast one object to another using AutoMapper or your own custom methods.
Keep your database entities separate from real world!
In detail
There are so many problems that you will encounter:
Disclosure of sensitive data. Your database entity could/will contain sensitive data which end-users shouldn't receive;
Performance issues and waste of RAM and CPU. It would be better to load only those properties that end-users is required, instead all;
Serialization problems. EF entities almost always contain Navigation properties which will be serialized together in case lazy-loading enabled. Imagine dozens related entities, which will be lazy-loaded when your composite root is being serialized. It will cause dozens unexpected requests to database;
Fragility. Any changes related your EF entities will affect on Presentation Layer and on end-users. For instance, in case with API, new added property just extend response, but deleted or renamed will break logic in your customers' application.
There are a lot of other problems, just be careful.
I would recommend not Serializing Entity Framework classes and creating a specific class that only inherits from Object and has only the data you need

breezeManager.createEntity() fails to populate foreign key property for a specific value

I have two relevant tables here:
public partial class List
{...
public int RegionId { get; set; }
[ForeignKey("RegionId")]
public virtual Region Region { get; set; }
...}
public partial class Region
{
public Region()
{
Lists = new HashSet<List>();
}
public int RegionId { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
public DateTime Added { get; set; }
public virtual ICollection<List> Lists { get; set; }
}
Here's the contents of the Regions table:
RegionId Name
1 Global
2 China
3 USA
4 UK
8 Canada
9 Spain
10 France
On the breeze side of things, I pull down the Regions:
var query = new breeze.EntityQuery().from("Regions").select("RegionId,Name").orderBy("RegionId");
return $rootScope.breezeManager.executeQuery(query).then(function (data) {
service.regions = data.results;
It seems to work:
service.regions[2]; // Name: "USA", RegionId: 3
However, when I try to create a new entity:
var newList = $rootScope.breezeManager.createEntity('List', listValues);
And in listValues, I specify { RegionId: 3, ...}:
newList.RegionId // 3
newList.Region // null
That would be strange already perhaps, but the really frustrating thing is, if I specify another value, like 1, it works. Same for 2, and 4:
newList.RegionId // 1
newList.Region.Name // "Global"
I've been poring through the code (and the internet) for hours trying to figure this out, but it's eluded me, and thus qualifies for my first ever SO question!
Update
I'm now even more confused. I planned to workaround this by manually setting the Region after the createEntity call, so I added this line of code right above createEntity:
var region = Enumerable.From(service.regions).Single("$.RegionId == " + listValues.RegionId);
However, after doing so, and with no other changes, newList now correctly gets a populated Region, even for 3 (USA)! I then commented out that line and tried again, and it still worked. Tried a few other times, various combinations of things, and now it's not working again, even with that line. Not sure if that helps. I'll keep experimenting.
I don't know what you're trying to do exactly but I do see that you have a fundamental misunderstanding.
I believe you are expecting your first query to return Region entities and you think that service.regions is populated with Region entities in the success callback.
Neither is true. Your query contains a select() clause which makes it what we call a projection. A projection returns data objects, not entities. There are no Region entities in cache either.
You may have seen elsewhere - perhaps a Pluralsight video - where a projection query did return entities. That happens when the query includes a toType clause which actually casts the projected data into instances of the targeted type. That's a trick you should only perform with great care, knowing what you are doing, why, and the limitations. But you're not casting in this query so this digression is besides the point.
It follows that the service.regions array holds some data objects that contain Region data but it does not hold Region entities.
This also explains why, when you created a new List entity with RegionId:3, the new entity's Region property returned null. Of course it is null. Based only on what you've told us, there are no Region entities in cache at all, let alone a Region with id=3.
I can't explain how you're able to get a Region with id=1 or id=2. I'm guessing there is something you haven't told us ... like you acquired these regions by way of some other query.
I don't understand why you're using a projection query in the first place. Why not just query for all regions and be done with it?
breeze.EntityQuery.from("Regions").orderBy("RegionId")
.using(manager).execute(function(data) {
service.regions = data.results;
});
I don't understand your update at all; that doesn't look like a valid EF query to me.
Tangential issues
First, why are you using a HashSet<List> to initialize the Lists property in your server-side Region model class? That's a specialized collection type that only confuses matters here. It doesn't do what the casual reader might think it does. While it prevents someone from adding the same object reference twice, it doesn't do the more important job of preventing someone from adding two different List objects with the same RegionId. The simple, obvious, and correct thing to do is ...
Lists = new System.Collections.Generic.List<List>();
// the full type name is only necessary because you burned the name "List"
// when defining your model class.
Second, on the client-side, please don't extend the Angular $rootScope with anything. That kind of global variable "pollution" is widely regarded as "bad practice". Keep your Breeze stuff inside a proper Angular service and inject that service when you need something.

Handling avoiding "duplicate" rows in EF on non-key fields in async scenarios

I currently have an object like this (simplified):
public class Image {
public int Id { get; set; }
public int ExternalId { get; set; }
}
Now let's say I have this method (mostly pseudo-code):
public void GetImage(int externalId) {
var existingImage = db.Images.FirstOrDefault(i => i.ExternalId == externalId);
if (existingImage != null) {
return existingImage;
}
var newImage = new Image() { ExternalId = externalId };
db.Images.Attach(newImage);
db.SaveChanges();
return newImage;
}
Because ExternalId isn't a key, the change tracker won't care if I have "duplicate" images in the tracker.
So now, let's say this method gets called twice, at the same time via AJAX and Web API (my current scenario). It's async, so there are two threads calling this method now.
If the time between calls is short enough (in my case it is), two rows will be added to the database with the same external ID because neither existing check will return a row. I've greatly simplified this example, since in my real one, there's a timing issue as I fetch the "image" from a service.
How can I prevent this? I need the image to be returned regardless if it's new or updated. I've added a Unique Constraint in the database, so I get an exception, but then on the client, the call fails whereas it should use the existing image instead of throwing an exception.
If I understand EF correctly, I could handle this by making ExternalId a primary key and then use concurrency to handle this, right? Is there any way to avoid changing my current model or is this the only option?
If you already have property defining uniqueness of your entity (ExternalId) you should use it as a key instead of creating another dummy key which does not specify a real uniqueness of your entity. If you don't use ExternalId as a key you must put unique constraint on that column in the database and handle exception in your code to load existing Image from the database.

Modeling Question for RavenDB (Or other doc oriented databases)

Wondering how some of the more experienced (or anyone with a better idea than I have) would tackle my particular modeling scenario...
I have a typical "Category -> SubCategory ->TertiarySubCategory" scenario and I'm not sure if I'm mapping it out correctly. I am mapping this directly to an MVC route since raven seems to lend itself well with this. Under the final category (which can be at the first, 2nd or 3rd levels there will be a list of items associated with only that level of a category. So, we might have something like:
Single level category: '/Politics/'
Second level category: 'Politics/People' or 'Politics/Websites'
Tri-Level Category: 'Sports/Pro/Volleyball' or 'Sports/College/Football'
In a traditional RDBMS this is easy through primary/foreign keys + a few joins... so, wondering how I would handle with Raven?
From what I have read should I store the entire 'sports/pro/volleyball' URI or Key in a list of items that fall under it?
i.e. -
public class CategoryItem
{
public string FriendlyName {get;set;} // Volleyball or Pro Volleyball
public string CategoryURI {get;set;} // i.e. - "/sports/pro/volleyball/"
public string content {get;set;} // i.e. - "Who is the best Pro Volleyball Athlete?"
public List<string> Comments {get;set;}
}
// then we could store something like this:
var survey1 = new CategoryItem();
survey1.CategoryURI = "/sports/pro/volleyball/"
survey1.Content = "Who is the best female pro volleyball player?";
survey1.Comments.Add(new Comment("Misty May"));
var survey2 = new CategoryItem();
survey2.CategoryURI = "/sports/pro/volleyball/";
survey2.Content = "Who is the best male pro volleyball player?";
survey2.Comments.Add(new Comment("Some guy I don't kow");
// asuumes ravenSession was alreadyopened...
ravenSession.Store(survey1);
ravenSession.Store(survey2);
ravenSessoin.SaveChanges();
//{ ...... etc ..... }
//Then I can query by CategoryURI without needing joins (denormalization).... i.e. -
var items = session.Query<CategoryItem>()
.Where(x => x.CategoryURI == "/sports/pro/volleyball/");
Or should I create a List items member of the actual category class? Each item would have a list of it's own comments... meaning everything's stored in a single document within Raven - i.e. -
public class Category
{
public string FriendlyName {get;set;} // i.e. - "Volleyball" or "Pro Volleyball"
public string URI {get;set;} // i.e. - "/sports/pro/volleyball" which is the MVC path
public List<CategoryItem> Items {get;set;}
}
public class CategoryItem
{
public string Content {get;set;}
public List<string> Comments {get;set;}
}
var vballCat = new Category();
vballCat.FriendlyName = "Pro Volleyball";
vballCat.URI = "/sports/pro/volleyball/"; // equivalent to the MVC route
var catItem = new CategoryItem().
catItem.Content = "Who is the best male pro volleyball player?";
catItem.Comments.Add("Misty May");
catItem.Comments.Add("Some Guy 1");
vballCat.Items.Add(catItem);
ravenSession.Store(vballCat);
ravenSession.SaveChanges();
..... now once I pull the primary cat i.e. - "/sports/pro/volleyball/" I have everything I need already under it
var items = session.Query<Category>()
.Where(x => x.URI == "/sports/pro/volleyball/");
{ ............. etc ............... }
Now here I can just iterate through the Items collection and it's collection of comments.... does this use eager loading? What if I had a million comments under one category item? When I load the main category would it load all one million comments too!?!?
I would appreciate any help you can provide. Sorry if this example/question is unclear... I'll try to clarify anything if you guys need it. Thanks again!
The answer is that it depends on the size of your data and your usage scenario.
The first example is useful if you have large number of items and want to access categories without its items.
The second example is useful if you usually access category with its items, and the size of items is limited (note that limited is still high, several thousands wouldn't cause me to blink).
Note that there is no such thing as eager / lazy loading in RavenDB, you are talking about a single document vs. multiple documents, not about relations between documents. The entire document is loaded when you need it.
Another thing to remember is that it is usually faster to query by id than querying. That means that if you have ids that already looks very much like Document Ids, you might as well MAKE them the document ids.

EF4 POCO one to many Navigation property is null

I'm using VS2010, EF4 feature CTP (latest release), and POCO objects, such as the example below:
class Person
{
public int ID { get; set; }
public string Name { get; set; }
public virtual IList<Account> Accounts { get; set; }
...
}
class Account
{
public string Number { get; set; }
public int ID { get; set; }
...
}
For the sake of brevity, assume context below is the context object for EF4. I have a dbml mapping between entity types and the database, and I use it like this with no problem:
Person doug = context.Persons.CreateObject();
doug.Name = "Doug";
context.Add(doug);
context.Save();
doug.Accounts.Add(new Account() { Name = "foo" });
context.Save(); // two calls needed, yuck
At this point, the database has a Person record with the name "Doug", and an account record "foo". I can query and get those record back just fine. But if I instead try to add the account before I save the Person, the Accounts list is null (the proxy hasn't created an instance on that property yet). See the next example:
Person doug = context.Persons.CreateObject();
doug.Name = "Doug";
doug.Accounts.Add(new Account() { Name = "foo" }); // throws null reference exception
context.Add(doug);
context.Save();
Has anybody else encountered this? Even better, has anyone found a good solution?
Person doug = context.Persons.CreateObject();
doug.Name = "Doug";
context.Add(doug);
doug.Accounts.Add(new Account() { Name = "foo" });
context.Save();
This will work
Yes and yes!
When you new the POCO up (as opposed to CreateObject from the Context), no proxies are provided for you. This may seem obvious, but I had to explicitly remind myself of this behavior when chasing a similar issue down. (I know this isn't the situation you described in the question, but the overall issue should be acknowledged).
Initializing collections in the constructor of the POCO does not interfere with proper EF4 proxy lazy-loading behavior, from what I've observed in my own testing.
OK, all this being said, I now see your comment to the previous answer -- why don't I have a proxied Addresses collection when I request a new Person from my context? Do you have lazy loading enabled on the context? Seeing how we're dealing with navigation properties, I could see where having lazy loading turned off may make a difference in this situation.
ISTM that if you expect the framework to do all this for you then you wouldn't really have a "POCO", would you? Take your Person class, with the code above. What would you expect the state of the Accounts property to be after construction, with no constructor, if the EF weren't involved? Seems to me that the CLR will guarantee them to be null.
Yes, proxies can initialize this when necessary for materialization of DB values, but in the EF, "POCO" actually means "Plain". Not "something packed with runtime-generated code which we pretend is 'Plain'".