different hashtable cacheItem with similar data values or separate cacheItems for each data value – which is an efficient approach? - asp.net

I have broadly two different classes of data caching requirements based on data size:
1) very small data (2-30 characters) – this includes such things as the type code for a given entityId. The system is based upon the concept of parent-child entity hierarchy and actions are authorized against values that are built in combination with entity type code. Caching these type codes for different entities saves time on db fetch.
2) medium/Large data – This is general data like products description and pages.
I'm confused as to which approach is better suited for first class of data.
I can cache it like this:
HttpRuntime.Cache.Insert("typeCode" + entityId, entityTypeCode);
or like this:
Dictionary<int, string> etCodes =
(Dictionary<int, string>)HttpRuntime.Cache["typeCode"];
etCodes[entityId] = entityTypeCode;
Clearly, In the second approach, I'm saving on unnecessary cache items for each entityId.
or, having Cache object populated with several items of such small size is okay.
Which of these approachs is good in terms of performance and overhead?

Personally I would take your second approach of one single object and use a custom object instead of a Dictionary.
This would enable me to later control more aspects like expiration of items within the object or changing the implementation.
I would do it similar to this:
public class MyCacheObject
{
public static MyCacheObject
{
get
{
// ...Omitted locking here for simplification...
var o = HttpRuntime.Cache["MyCacheObject] as MyCacheObject;
if ( o = null )
{
o = new MyCacheObject();
HttpRuntime.Cache["MyCacheObject] = o;
}
return o;
}
}
public object GetEntity( string id, string code )
{
// ...
}
public void SetEntity( object entity, string id, string code )
{
// ...
}
// ...
}
If you have a custome base class for the entities, the GetEntity and SetEntity methods could be optimized further.

Related

Loading multiple sets of data in a content page in ASP.NET MVC Entitiy Framework

I need to load multiple entity types in my View page. I am using ViewModel for this purpose. However, I need to make around 5-6 database calls to load each set of data and assign them to the relevant property of the ViewModel. I wonder if this is a recommended approach since it requires multiple database calls. Or, am I being over-concerned about this? Here is a snapshot from my code:
var model = new EntryListVM();
string userid = "";
if (ViewBag.CurrentUserId == null)
userid = User.Identity.GetUserId();
else
userid = ViewBag.CurrentUserId;
ViewBag.CurrentUserId = userid;
//First database call
model.DiscussionWall = db.DiscussionWalls.Find(wallId);
//Second database call to learn if the current students has any entry
model.DiscussionWall.DoesStudentHasEntry = db.Entries.Any(ent => ent.DiscussionWallId == wallId && ent.UserId == userid);
model.PageIndex = pageIndex;
//Third database call
model.TeacherBadges = db.Badges.Where(b => b.CourseId == model.DiscussionWall.CourseId && b.IsSystemBadge == false && b.IsEnabled == true).ToList();
//Fourth database call
model.Reactions = db.Reactions.Where(re => re.CourseId == model.DiscussionWall.CourseId).ToList();
int entryPageSize = Convert.ToInt32(ConfigurationManager.AppSettings["EntryPageSize"]);
int firstChildSize = Convert.ToInt32(ConfigurationManager.AppSettings["FirstChildSize"]);
List<ViewEntryRecord> entryviews = new List<ViewEntryRecord>();
bool constrainedToGroup = false;
if (!User.IsInRole("Instructor") && model.DiscussionWall.ConstrainedToGroups)
{
constrainedToGroup = true;
}
//Fifth database call USING VIEWS
//I used views here because of paginating also to bring the first
//two descendants of every entry
entryviews = db.Database.SqlQuery<ViewEntryRecord>("DECLARE #return_value int;EXEC #return_value = [dbo].[FetchMainEntries] #PageIndex = {0}, #PageSize = {1}, #DiscussionWallId = {2}, #ChildSize={3}, #UserId={4}, #ConstrainedToGroup={5};SELECT 'Return Value' = #return_value;", pageIndex, entryPageSize, wallId, firstChildSize, userid, constrainedToGroup).ToList();
model.Entries = new List<Entry>();
//THIS FUNCTION MAP entryviews to POCO classes
model.Entries = ControllerUtility.ConvertQueryResultsToEntryList(entryviews);
//Sixth database call
var user = db.Users.Single(u => u.Id == userid);
model.User = user;
I wonder if this is too much of a burden for the initial page load?
I could use SQL-View to read all data at once, but I guess I would get a too complicated data set to manage.
Another option could be using Ajax to load the additional results after the page loading (with the main data) is completed. For example, I could load TeacherBadges with AJAX after the page is being loaded.
I wonder which strategy is more effective and recommended? Are there specific cases when a particular strategy could be more useful?
Thanks!
It all depends on your scenario - different scenarios have different ways of doing things. There is no single right way of doing things that are similar in nature. What might work for me might not work for you. Ever heard that saying: there are many ways to kill a cat? Well this certainly applies to programming.
I am going to answer based on what I think you are asking. Your questions are very broad and not that specific.
However, I am not sure if this is a recommended approach since it
requires multiple database calls.
Sometimes you need to do one database call to get data, and sometimes you need to do more than one database call to get the data. For example:
User details with addresses: one call for user and one call for addresses
User details: one call
I am using ViewModel for this purpose.
Using view models for your views is a good thing. If you want to read up more on what I had to say about view models then you can go and read an answer that I gave on the topic:
What is ViewModel in MVC?
View models are ideal for when you have data that is coming from multiple datasets. View models can also be used to display data coming from one dataset, for example:
Displaying user details with multiple addresses
Displaying only user details
I read the data in the controller in separate linq statements, and
assign them to the relevant List property of the ViewModel.
I would not always return a list - it all depends on what you need.
If I have a single object to return then I will populate a single object:
User user = userRepository.GetById(userId);
If I have a list of objects to return then I will return a list of objects:
List<User> users = userRepository.GetAll();
It is of no use to return a single object and then to populate a list for this object:
List<User> user = userRepository.GetByUserId(userId).ToList();
Second option could be using SQL-View to read all data with one
database call, and then map them to the entities properly in
controller.
This is similar to your first question, how you return your data on the database level is up to you. It can be stored procedures or views. I personally prefer stored procedures. I have never used views before. Irrespective of what you choose your above mentioned repository methods should still look the same.
Third option could be using Ajax to load the additional results after
the page loading (with the main data) is completed.
You can do this if you want to. I would not do it if it is not really needed. I try to load data on page load. I try to get as much data on the screen before the page is fully loaded. There have been times that I had to go the AJAX route after the page was loaded. After the page was loaded I had to do an AJAX call to load my HTML table.
If you really just need to have data displayed then do just that. You do not need any fancy ways of doing this. Maybe later you need to change on screen data, then AJAX is cool to use.
I wonder which strategy is more effective and recommended? Are there
specific cases when a particular strategy could be more useful?
Let us say you want to display a list of users. We do a database call and return the list to the view. I do not normally use view models if I only return a list:
public class UserController : Controller
{
private IUserRepository userRepository;
private IAddressRepository addressRepository;
public UserController(IUserRepository userRepository, IAddressRepository addressRepository)
{
this.userRepository = userRepository;
this.addressRepository = addressRepository;
}
public ActionResult Index()
{
List<User> users = userRepository.GetAll();
return View(users);
}
}
And your view could look like this:
#model List<YourProject.Models.User>
#if (Model.Count > 0)
{
foreach (var user in Model)
{
<div>#user.Name</div>
}
}
If you need to get a single user's details and a list of addresses, then I will make use of a view model because now I need to display data coming from multiple datasets. So a user view model can look something like this:
public class UserViewModel
{
public UserViewModel()
{
Addresses = new List<Address>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Address> Addresses { get; set; }
}
The your details action method could look like this:
public ActionResult Details(int id)
{
User user = userRepository.GetById(id);
UserViewModel model = new UserViewModel();
model.Name = user.Name;
model.Addresses = addressRepository.GetByUserId(id);
return View(model);
}
And then you need to display the user details and addresses in the view:
#model YourProject.ViewModels.UserViewModel
<div>First Name: #Model.Name</div>
<div>
#if (Model.Addresses.Count > 0)
{
foreach (var address in Model.Address)
{
<div>#address.Line1</div>
<div>#address.Line2</div>
<div>#address.Line3</div>
<div>#address.PostalCode</div>
}
}
</div>
I hope this helps. It might be to broad of an answer but it can guide you on the correct path.
Includes for linked data
For linked data it's simple (you probably know this way):
var users = context.Users.Include(user => user.Settings).ToList();
It queries all users and pre-loads Settings for each user.
Use anonymous class for different data sets
Here is an example:
context.Users.Select(user => new
{
User = user,
Settings = context.Settings
.Where(setting => setting.UserId == user.Id)
.ToList()
}).ToList();
You still kinda need to choose your main query collection (Users in this case), but it's an option. Hope it helps.

LINQ and web service cannot return anonymous types, and you cannot construct an object in a query?

Web services cannot return an anonymous type.
If you are building a LINQ query using classes through a datacontext... you cannot construct instances of those classes in a query.
Why would I want to do this? Say I want to join three "tables" or sets of objects. I have three items with a foreign key to each other. And say the lowest, most detailed of these was represented by a class that had fields from the other two to represent the data from those. In my LINQ query I would want to return a list of the lowest, most detailed class. This is one way I have decided to "join some tables together" and return data from each of them via LINQ to SQL via a WebService. This may be bad practice. I certainly do not like adding the additional properties to the lowest level class.
Consider something like this... (please ignore the naming conventions, they are driven by internal consideration) also for some reason I need to instantiate an anonymous type for the join... I don't know why that is... if I do not do it this way I get an error...
from su in _dataContext.GetTable<StateUpdate>()
join sfs in _dataContext.GetTable<SystemFacetState>()
on new { su.lngSystemFacetState } equals new { lngSystemFacetState = sfs.lngSystemFacetState }
join sf in _dataContext.GetTable<SystemFacet>()
on new { sfs.lngSystemFacet } equals new { lngSystemFacet = sf.lngSystemFacet }
join s in _dataContext.GetTable<System>()
on new { sf.lngSystem } equals new {lngSystem = s.lngSystem}
select new
{
lngStateUpdate = su.lngStateUpdate,
strSystemFacet = sf.strSystemFacet,
strSystemFacetState = sfs.strSystemFacetState,
dtmStateUpdate = su.dtmStateUpdate,
dtmEndTime = su.dtmEndTime,
lngDuration = su.lngDuration,
strSystem = s.strSystem
}
).ToList();
Notice I have to build the anonymous type which is composed of pieces of each type. Then I have to do something like this... (convert it to a known type for transport via the web service)
result = new List<StateUpdate>(from a in qr select(new StateUpdate
{
lngStateUpdate = a.lngStateUpdate,
strSystemFacet = a.strSystemFacet,
strSystemFacetState = a.strSystemFacetState,
dtmStateUpdate = a.dtmStateUpdate,
dtmEndTime = a.dtmEndTime,
lngDuration = a.lngDuration,
strSystem = a.strSystem
}));
It is just awful. And perhaps I have created an awful mess. If I am way way off track here please guide me to the light. I feel I am missing something fundamental here when I am adding all these "unmapped" properties to the StateUpdate class.
I hope someone can see what I am doing here so I can get a better way to do it.
You can create a 'dto' class which just contains the properties you need to return and populate it instead of the anonymous object:
public class Result
{
public string lngStateUpdate
{
get;
set;
}
... // other properties
}
then use it like this:
from su in _dataContext.GetTable<StateUpdate>()
...
select new Result
{
lngStateUpdate = su.lngStateUpdate,
... // other properties
}
Nitpick note - please ditch the Hungarian notation and camel casing for properties :)
I think the answer is to create another object to serve as a DTO. This object would not be mapped to the data context and can contain fields that cross the mapped objects. This solves the problems of repetitive properties in the mapped objects, and allows for instantiation of the DTO class in the query as it is not mapped.
FYI: with respect to the problem with the join- I revisited that and I think I may have had the inner and outer components of the join switched around before.

C# database access, Dapper, SQL and POCOs - programming design

Let's say we have a table in SQL represented in C# like this:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Picture { get; set; } // filename of the picture, e.g. apple.jpg
public int CategoryID { get; set; }
}
Now we would query the database and retrieve the object, let's say with values like this:
ID = 1
Name = Yellow apple
Picture = apple.jpg
CategoryID = 25
All perfectly normal. The thing I'm meditating about at the moment is this: if I want to show a product, I need some additional info that wasn't queried from the database, like exact file path to the image, all we have is
apple.jpg
, but we need maybe something like
~/images/apple.jpg
So, I was thinking of 3 possibilities:
1.) add a new property to the class Product
public string PictureUrl
{
get
{
return "~/images/apple.jpg";
}
}
2.) specify the full url during performing of the presentation logic, let's say:
public void ShowProductDetails()
{
Product p = ProductRepo.GetProduct(id);
txtName.Text = p.Name;
imgPicture.ImageUrl = "~/images/" + p.Picture;
}
3.) use Decorator pattern
First approach seems wrong to me (even though I have been using it for quite a long time), because I'm trying to have a layered web application. I'm not sure hard-coding this is a good way to go.
Second approach is better, but worse in the sense it can't be easily reused. If I have multiple places where I'm doing the same thing and something changes, ... Maybe it would work if I specify some static constants holding the paths...
Third possibility seems quite complicated in terms of maintainability. The number of my classes would probably have to double. If I have 30 classes now, it would suddenly become 60 :/
What is the best/recommended way of doing things like this? If I add properties to my POCOs that aren't included in the db schema, I'm unable to use Dapper.Contrib or Rainbow and similar libraries, because even though "selects" work fine, I can't "insert" nor "delete". I have to hard-code the sql strings for every command which becomes really tedious after some time, when you're doing all the time the same stuff.
EDIT:
The solution from Govind KamalaPrakash Malviya is great, but can't be used every time. I need a way to solve this for any type of properties, even those more complex ones - for instance the number of photos of some album. It's a good idea to query the count of photos along with albums, but assign it to what? Create a decorated class using a Decorator pattern?
How do YOU solve this kind of architecture problems?
I think you should manipulate it in presentation layer because image path for presentation layer only. so use third one but make it easy using utility method
public class PathUtility
{
public static string ImageUrl(string imageName)
{
if(string.IsNullOrEmpty(imageName))
{
throw new Exception("Image name not valid!!");
}
else
{
return "YourImageDirectroyUrl" + imageName;
}
}
}
and use it easily
PathUtility.ImageUrl("apple.jpg");
I normally solve this by leaving the entity object as it is and creating an extra data container, which will either hold a reference to the corresponding entity or implement the corresponding properties from the entity object itself. In the latter case I use a mapping library (AutoMapper) to copy data from an entity to a the enhanced container.
The logic for filling the extra properties normally lies in a factory (or factory method). It's up to you, where you want to place this in your architecture. In a current project we are including them in our data access facade on client side, because we don't want to clutter the data access layer with too many DTO's. This of course means, that the data access layer still needs to support retrieving the extra properties. In your case an operation like int GetNumberOfPhotosForAlbum(Album album).
We found that the benefits outweigh the risk of an ever-growing contract of the data access layer, which of course might need to support many different calls like the example above instead of just EnhancedAlbum GetEnhancedAlbumWithAllKindsOfExtraProperties(long albumId). This might also become a performance problem in some scenarios, because of the overhead of an increased frequency of service calls. In the end you need to decide, what's best for your project.
I like this approach, because my entities (Album) stay untouched and I retain a clear separation of concerns between persistence, client logic and mapping.
Example:
class Album
{
string Name { get; set; }
}
class EnhancedAlbum
{
Album Album { get; set; }
int NumberOfPhotos { get; set; }
}
class EnhancedAlbumFactory
{
private MyDataService _dataService;
//include some means of constructing or (better) injecting the data service
EnhancedAlbum GetEnhancedAlbum(Album album)
{
return new EnhancedAlbum
{
Album = Album,
NumberOfPhotos = _dataService.GetNumberOfPhotosForAlbum(album);
};
}
}

Can I use NHibernate Criteria to project an entity and its child collection onto a class?

I'm using NH Criteria to retrieve an entity and project selective fields onto a custom class (a bit like projecting data onto a ViewModel for display on an MVC view).
This is easy enough using ProjectionList:
var emailCriteria = mSession.CreateCriteria<Email>();
emailCriteria.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("Subject"), "Subject")
);
emailCriteria.SetResultTransformer(Transformers.AliasToBean<EmailDataModel>());
var result = emailCriteria.List<EmailDataModel>();
However, my entity contains a collection, and I want to bring that back too, and project it as a collection onto my custom class.
My domain model looks (in simplified form) like this:
public class Email {
public string Subject
public List<EmailAttachment> Attachments
etc...
}
public class EmailAttachment {
public UploadedFile File
}
public class UploadedFile {
public string Filename
public UploadedFileData Data
}
public class UploadedFileData {
public byte[] Data
}
Here's the "data model" classes I want to project onto:
public class EmailDataModel {
public string Subject
public List<EmailAttachmentDataModel> Attachments
}
public class EmailAttachmentDataModel {
public string Filename
public byte[] Data
}
Now I know these models look very similar, and you'd be forgiven for thinking "what's the point?", but that's because I've simplified them. It's nice to be able to flatten my domain objects into handy data models.
My big problem is figuring out how to access the necessary fields from deep down in my child objects (in this case, UploadedFile.Filename and UploadedFileData.Data), and project them as an EmailAttachmentDataModel collection onto my EmailDataModel.
I've read a lot of articles online which discuss accessing child collections - using either EmailCriteria.CreateAlias or EmailCriteria.CreateQuery - but I haven't found anything which explains how to project a child collection AS a collection.
I hope this will be a useful exercise for anyone interested in tinkering with NH Criteria queries.
Ok, I think I've resolved this upgrading to NHibernate 3 and using QueryOver. Here's what my code looks like now:
//Declare entities
Email email = null;
EmailAttachment attachment = null;
UploadedFile file = null;
Byte[] fileData = null;
//Select data from parent and child objects
var results = mSession.QueryOver<QueuedEmail>(() => email)
.JoinAlias(() => email.Attachments, () => attachment, JoinType.LeftOuterJoin)
.JoinAlias(() => attachment.File, () => file, JoinType.LeftOuterJoin)
.JoinAlias(() => file.Data, () => fileData, JoinType.LeftOuterJoin)
.TransformUsing(Transformers.DistinctRootEntity)
.List<Email>()
//Loop through results projecting fields onto POCO
.Select(x => new EmailDataModel()
{
Id = x.Id,
Body = x.Body,
AttachmentCount = x.Attachments.Count(),
FromAddress = x.FromAddress,
//Loop through child collection projecting fields onto POCO
Attachments = x.Attachments.Select(attach => new EmailAttachmentDataModel()
{
Data = attach.File.Data.Data,
Filename = attach.File.Filename,
Id = attach.Id
}).ToArray() //NB Now projecting this collection as an array, not a list
}).ToArray();
So there it is. Our result is a flattened class which contains the data we need, plus a collection of attachments (which each contain just two fields from our data structure - nicely flattened).
Why should you do this?
It simplifies the result by flattening into only the fields I really want.
My data is now safely encapsulated in a class which can be passed around without fear of accidentally updating my data (which could happen if you just pass back NH data entities).
Finally (and most importantly), because the code above only generates one SELECT statement. Had I stuck with my original Criteria query, it would have generated one SELECT for each row, plus more for the children further down the chain. That's fine if you're dealing with small numbers, but not if you're potentially returning thousands of rows (as I will in this instance - it's a web service for an email engine).
I hope this has been useful for anybody wishing to push a bit further into NHibernate querying. Personally I'm just happy I can now get on with my life!

strongly typed sessions in asp.net

Pardon me if this question has already been asked. HttpContext.Current.Session["key"] returns an object and we would have to cast it to that particular Type before we could use it. I was looking at various implementations of typed sessions
http://www.codeproject.com/KB/aspnet/typedsessionstate.aspx
http://weblogs.asp.net/cstewart/archive/2008/01/09/strongly-typed-session-in-asp-net.aspx
http://geekswithblogs.net/dlussier/archive/2007/12/24/117961.aspx
and I felt that we needed to add some more code (correct me if I was wrong) to the SessionManager if we wanted to add a new Type of object into session, either as a method or as a separate wrapper. I thought we could use generics
public static class SessionManager<T> where T:class
{
public void SetSession(string key,object objToStore)
{
HttpContext.Current.Session[key] = objToStore;
}
public T GetSession(string key)
{
return HttpContext.Current.Session[key] as T;
}
}
Is there any inherent advantage in
using
SessionManager<ClassType>.GetSession("sessionString")
than using
HttpContext.Current.Session["sessionString"] as ClassType
I was also thinking it would be nice
to have something like
SessionManager["sessionString"] = objToStoreInSession,
but found that a static class cannot have an indexer. Is there any other way to achieve this ?
My thought was create a SessionObject which would store the Type and the object, then add this object to Session (using a SessionManager), with the key. When retrieving, cast all objects to SessionObject ,get the type (say t) and the Object (say obj) and cast obj as t and return it.
public class SessionObject { public Type type {get;set;} public Object obj{get;set;} }
this would not work as well (as the return signature would be the same, but the return types will be different).
Is there any other elegant way of saving/retrieving objects in session in a more type safe way
For a very clean, maintainable, and slick way of dealing with Session, look at this post. You'll be surprised how simple it can be.
A downside of the technique is that consuming code needs to be aware of what keys to use for storage and retrieval. This can be error prone, as the key needs to be exactly correct, or else you risk storing in the wrong place, or getting a null value back.
I actually use the strong-typed variation, since I know what I need to have in the session, and can thus set up the wrapping class to suit. I've rather have the extra code in the session class, and not have to worry about the key strings anywhere else.
You can simply use a singleton pattern for your session object. That way you can model your entire session from a single composite structure object. This post refers to what I'm talking about and discusses the Session object as a weakly typed object: http://allthingscs.blogspot.com/2011/03/documenting-software-architectural.html
Actually, if you were looking to type objects, place the type at the method level like:
public T GetValue<T>(string sessionKey)
{
}
Class level is more if you have the same object in session, but session can expand to multiple types. I don't know that I would worry about controlling the session; I would just let it do what it's done for a while, and simply provide a means to extract and save information in a more strongly-typed fashion (at least to the consumer).
Yes, indexes wouldn't work; you could create it as an instance instead, and make it static by:
public class SessionManager
{
private static SessionManager _instance = null;
public static SessionManager Create()
{
if (_instance != null)
return _instance;
//Should use a lock when creating the instance
//create object for _instance
return _instance;
}
public object this[string key] { get { .. } }
}
And so this is the static factory implementation, but it also maintains a single point of contact via a static reference to the session manager class internally. Each method in sessionmanager could wrap the existing ASP.NET session, or use your own internal storage.
I posted a solution on the StackOverflow question is it a good idea to create an enum for the key names of session values?
I think it is really slick and contains very little code to make it happen. It needs .NET 4.5 to be the slickest, but is still possible with older versions.
It allows:
int myInt = SessionVars.MyInt;
SessionVars.MyInt = 3;
to work exactly like:
int myInt = (int)Session["MyInt"];
Session["MyInt"] = 3;

Resources