List<T> caching, class iteration, count property - asp.net

Hy,
I have created a custom List, which tried to cache, but when getting back from cache, the cached object count is 0. Example code below:
List<CategoryEntry> categs = (List<CategoryEntry>)EPiServer.CacheManager.Get("test");
if(categs == null || categs.Count == 0)
{
categs = ConstructCategories();
EPiServer.CacheManager.Add("test", categs);
}
//Further down displaying the categories
UseCase:
First Pageload (after build) cache is empty, categs will be null,
Second Pageload cache will be, but will fail from get from there becouse categs.Count will be 0 and reconstructs the cache again and again....
the CategoryEntry class:
[serializable]
public class CategoryEntry{
public string Title { get; set; }
public string URL { get; set; }
public int CategoryId { get; set; }
public int CompanyPageId { get; set; }
public int ParentCategoryEntryId { get; set; }
public int Indent { get; set; }
}
The problem should be when saving the cache bc. it is saved as object, and when we get the cache we Cast to List<CategoryEntry>.
Also figured out if i do this with a List<string> instead of using List<CategoryEntry>
then the caching works perfectly!.
Example with List<string> which is working:
List<string> test = (List<string>)EPiServer.CacheManager.Get("sindex");
if (test == null)
{
test = new List<string>();
test.Add("item1");
test.Add("item2");
test.Add("item3");
test.Add("item4");
test.Add("item5");
EPiServer.CacheManager.Add("sindex", test);
}
else
{
Response.Write("It works: elements "+ test.Count);
}
Another Tryout was that i have cached a simple instance of CategoryEntry and that also works, the problem is when i try to save as List<CategoryEntry>
Any help Would be apreciated, thank you.

Related

How To Read and Write Records In SQLite Using SQLite Net Extensions?

Here is the documentation I've looked at and may be helpful: Sample SQLite OneToMany Unit Test and General Read and Write Documentation in Readme
My use-case is that I've already inserted an Item and I am now editing an Item. So I will need to basically update the Item record and insert n ItemPhoto records. Basically, I'mtalking about the case of SaveItem(..) where Item.Id != 0.
It seems that when I step through the code to write to the database I am seeing all of the keys being assigned to the objects in memory appropriately. However, later when I go to read an Item by calling GetWithChildren(..) in every case except one the ItemPhotos property has a Count of 0. The only time that ItemPhotos actually gets populated is the case when the ItemPhotoId is 0. My best guess is that somehow the ItemPhotoId is not being set before GetWithChildren(..) is run and then it only works when the default in-memory value of 0 actually matches the database's ItemPhotoId for the given Item.
Here is my code showing the models and the read and write code:
public class Item
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Text { get; set; }
public string Description { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<ItemPhoto> ItemPhotos { get; set; }
}
public class ItemPhoto
{
[PrimaryKey, AutoIncrement]
public int ItemPhotoId { get; set; }
[ForeignKey(typeof(Item))]
public int ItemId { get; set; }
public string FileLocation { get; set; }
[ManyToOne] // Many to one relationship with Item
public Item Item { get; set; }
}
class SqlLiteDataStore
{
static SQLiteConnection Database;
...
public Item GetItem(int id)
{
return Database.GetWithChildren<Item>(id, true);
}
public Item SaveItem(Item item)
{
// Simpler Attempt #1
// Database.InsertOrReplaceWithChildren(item);
// return item;
// Manual Attempt #2
if (item.Id != 0)
{
foreach (var photo in item.ItemPhotos)
{
if (photo.ItemPhotoId == 0)
Database.Insert(photo);
}
Database.UpdateWithChildren(item);
return item;
}
else
{
Database.InsertWithChildren(item, true);
return item;
}
}
...
}
Well I fixed it by dropping the existing tables and recreating them and beforehand just renaming the ItemPhoto's ItemPhotoId property to Id. Maybe the library assumes the primary key name of Id or maybe I changed something else along the way in terms of the models that just needed the tables to be recreated instead of migrated? Also, the simpler attempt at saving with just the Database.InsertOrReplaceWithChildren(item); seems to work just fine so I'm going with that for what it's worth.

SQLite.NET PCL returning 0 in all instances of autoincrement primary key

I am totally not getting this, because I have used this library in Xamarin apps for several years.
I have this base class that contains properties common in all db items:
public class BaseItem
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; } = 0; // SQLite ID
public long CreatedTimeSeconds { get; set; } = DateTime.Now.ToUnixTimeSeconds();
public long ModifiedTimeSeconds { get; set; } = DateTime.Now.ToUnixTimeSeconds();
}
Now, I derive from it:
[Table("CategoryTable")]
public class Category : BaseItem
{
public int CategoryTypeID { get; set; } = (int)CategoryType.Invalid;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
Here's a simplified version of what I'm seeing:
public class DBWorld
{
ISQLiteService SQLite { get { return DependencyService.Get<ISQLiteService>(); } }
private readonly SQLiteConnection _conn;
public DBWorld()
{
_conn = SQLite.GetConnection("myapp.sqlite");
}
public void TestThis()
{
_conn.CreateTable<Category>();
var category = new Category();
category.Name = "This Should Work";
int recCount = connection.Insert(category);
// at this point recCount shows as 1, and category.ID shows as zero.
// I thought Insert was supposed to set the autoincrement primary key
// regardless, it should be set in the database, right? So...
var categoryList = connection.Query<Category>($"SELECT * FROM {DBConstants.CategoryTableName}");
// at this point categoryList[0] contains all the expected values, except ID = 0
}
}
I am obviously missing something, but for the life of me, I can't figure out what...
Like so many other bizarre things that happen in the Visual Studio Xamarin world, when I went back later, this worked the way all of us expect. I guess Visual Studio was just tired and needed to be restarted.

List <T> store large amounts of data , Not enough memory

public class ListKeywords
{
public int ID { set; get; }
public string Keyword { set; get; } //关键词
public string Language { set; get; } //语种
public int WordCount { set; get; } //单词数
public int WordLength { set; get; } // 字符数
public int Status { set; get; } //采集状态 0-未采集 1-采集成功 2-保存失败 3-保存成功 4-发布失败 5-发布成功
public bool Taken { set; get; }
public bool FTPStatus { set; get; }
public bool DBStatus { set; get; }
public string UrlName { set; get; }
public ListKeywords()
{
}
public ListKeywords(string keyword)
{
this.Keyword = keyword;
}
}
List<string> lines = new List<string>();
List<ListKeywords> keywordsList = new List<ListKeywords>();
using (StreamReader sr = File.OpenText(filePath))
{
string s = String.Empty;
while ((s = sr.ReadLine()) != null)
{
//lines.Add(s); //Operating normally
eywordsList.Add(new ListKeywords("some keywords")); // Operating normally
keywordsList.Add(new ListKeywords(s)); // it will be out of memeory
}
}
In text file, have 1,000,000 line data, if i use above code to load the large data to list< keywordsList >, it will raises an OutOfMemoryException, but if i load it to list< string >, it run normally. How to solved it ?
Instead of using a List maybe try using an IEnumerable w/ yield?
static IEnumerable<ListKeywords> Keywords()
{
using (StreamReader sr = File.OpenText(path))
{
string s = String.Empty;
while ((s = sr.ReadLine()) != null)
{
yield return new ListKeywords(s);
}
}
}
Note that Jon Skeet's C# in Depth offers a great explanation about this in Chapter 6. I imagine he also has some articles or posts on StackOverflow about this topic. As he points out, you want to be careful about modifying this method to pass in a StreamReader (or TextReader as is used in his example) as you would want to take ownership of the reader so it will be properly disposed of. Rather, you would want to pass in a Func<StreamReader> if you have such a need. Another interesting note he adds here - which I will point out because there are some edge cases where the reader will not actually be properly disposed of even if you don't allow the reader to be provided by the caller - it's possible for the caller to abuse the IEnumerable<ListKeywords> by doing something like Keywords().GetEnumerator() - this could result in a memory leak and could even potentially cause security issues if you have security-related code which relies on the using statement to clean up the resource.

Custom impromptuobject for json.net deserialization

I was playing around with impromptu interface over a jobject and ran into the following issue
https://code.google.com/p/impromptu-interface/issues/detail?id=17
The issue is marked as 'Won't fix' and in the comments the author says that it could be fixed by implementing a custom impromptuobject.
Anyone have a sample of such an implementation? Or know another solution to this problem?
So the problem is that JArray has GetEnumerator() defined as interface-only, which makes the method no longer duck callable by the DLR. So below I've overriden the trygetmember to check if the result is a JArray's and convert it to a JEnumerable that implements GetEnumerator() in a dlr invokable way.
public class NonRecursiveJArrayConversionDictionary : ImpromptuDictionary{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if(base.TryGetMember(binder, out result)){
if(result is JArray){
result = ((JArray)result).AsJEnumerable();
}
return true;
}
result = null;
return false;
}
}
However, this will only work for json structures that don't have arrays more then one property deep. You'll either have modify the above to recursively check anytime anything is returned maybe with a proxy, or modify the dictionary indexer's set to check and convert when deserialized instead.
Update: Json.net verion >= 5.0.4.16101 and ImpromptuInterface >= 6.1.4 will work out of the box.
void Main()
{
ICustomer customer = Impromptu.ActLike(JObject.Parse(#"
{
Id: 1,
Name:'Test',
Location:'Somewhere',
Employees: [
{ Id:1, EmployerId:39421, Name:'Joe' },
{ Id:2, EmployerId:39421, Name:'Jane' },
]
}
"));
foreach(var employee in customer.Employees){
employee.Id.Dump();
employee.Name.Dump();
}
}
public interface ICustomer
{
int Id { get; set; }
string Name { get; set; }
string Location { get; set; }
IList<IEmployee> Employees { get; }
}
public interface IEmployee
{
int Id { get; set; }
int EmployerId { get; set; }
string Name { get; set; }
}

CodeActivity InArgument<T> accessing values of T

I have a bit of a twist that is a little more trouble than I thought it would be. Normally I would have an InArgument and use it as below:
public InArgument<Int32> XYZ_ID { get; set; }
public InArgument<Int32> XYZ_COUNT { get; set; }
protected override IAsyncResult BeginExecute(...)
{
....snip....
_ABC_ID = XYZ_ID.Get(context),
_ABC_Count = XYZ_COUNT.Get(context)
This works great and I thought a custom object we be close to the same process but I can't seem to figure it out. ActvUsrPrgmResults is just a class of properties such as AccountName, FirstName etc. So I passed it in like any other type.
public InArgument<bool> IsHappy { get; set; }
public InArgument<bool> IsClapping { get; set; }
public InArgument<ActvUsrPrgmResults> itm_ActvUsrPrgm { get; set; }
Accessing it though is a bit more difficult....for me.
protected override void Execute(CodeActivityContext context)
{
NewPerson x = new NewPerson
{
AccountName = this.itm_ActvUsrPrgm.Get(?????
//this doesn't work either
AccountName = itm_ActvUsrPrgm.?????
In other words I can't see how to access the properties of the itm_ActvUsrPrgm InArgument.
Thank You for any help or direction
JB
Additional Info
I have this CodeActivity in a ForEach (List). So each item in the generic collection is a single instance of ActvUsrPrgmResults. So I hand this off to my CodeActivity thinking I will have a handle to manipulate that item's data????
Interesting
Now based upon Will's comments I got to thinking about this slight of hand. It works but shouldn't there be a more elegant approach?
public InArgument<bool> IsHappy { get; set; }
public InArgument<bool> IsClapping { get; set; }
public InArgument<ActvUsrPrgmResults> itm_ActvUsrPrgm { get; set; }
protected override void Execute(CodeActivityContext context)
{
ActvUsrPrgmResults y = itm_ActvUsrPrgm.Get(context);
NewPerson x = new NewPerson
{
AccountName = y.AccountName....
The problem is me, myself, and I. I wasn't getting a handle on the object being passed in. For some under the covers reason an "InArgument" is not immediately accessible until you get a firm grasp on the exact object from the given context. I don't know for sure but I suspect this is due to multiple workflows running so you can't just grab any ole object ytou must get the object from the proper context. Anyway here are my comments of what I learned inline.
public InArgument<bool> IsHappy { get; set; } //bool variable being passed in
public InArgument<bool> IsClapping { get; set; } //bool variable being passed in
public InArgument<ActvUsrPrgmResults> itm_ActvUsrPrgm { get; set; } //custom object being passed in
protected override void Execute(CodeActivityContext context)
{
bool Happy = context.GetValue(this.IsHappy);
bool Clap = context.GetValue_this.IsClapping);
ActvUsrPrgmResults y = context.GetValue(this.itm_ActvUsrPrgm);
//NOW!!! we have a handle to the proper objects for this context
//This also works. I just flip flopped the InArgument property and the context.
ActvUsrPrgmResults y = itm_ActvUsrPrgm.Get(context);
NewPerson x = new NewPerson
{
AccountName = y.AccountName....

Resources