Is this do-able?
Here's my situation and could you suggest an easier or more efficient way if what I'm trying to do isn't advisable.
We're talking about report generation page here.First, I have a stored procedure that takes a REALLY long time to finish executing if no filters/condition is set. Meaning it is a view all, this stored proc returns a list. This list then populates a table in my view. It could be just 10 up to thousands records but the execution is pretty long because it computes this and that against thousands of record, to make it short, I won't alter my stored procedure.
Now from this first view, I have a printable version button which calls another page with the same contents but print-friendly page. I dont want to execute the painful stored proc to get the same list, I want to re-use what is already generated. How can I do this?
From what I understand you are thinking of implementing some way of caching the data that you calculated through a painfully slow stored procedure?
One option would be to implement a CacheManager and cache the results for a certain period of time:
/// <summary>
/// Cache Manager Singleton
/// </summary>
public class CacheManager
{
/// <summary>
/// The instance
/// </summary>
private static MemoryCache instance = null;
/// <summary>
/// Gets the instance of memoryCache.
/// </summary>
/// <value>The instance of memoryCache.</value>
public static MemoryCache Instance
{
get
{
if (instance == null)
{
instance = new MemoryCache();
}
return instance;
}
}
}
/// <summary>
/// Cache Manager
/// </summary>
public class MemoryCache
{
/// <summary>
/// Gets the expiration date of the object
/// </summary>
/// <value>The no absolute expiration.</value>
public DateTime NoAbsoluteExpiration
{
get { return DateTime.MaxValue; }
}
/// <summary>
/// Retrieve the object in cache
/// If the object doesn't exist in cache or is obsolete, getItemCallback method is called to fill the object
/// </summary>
/// <typeparam name="T">Object Type to put or get in cache</typeparam>
/// <param name="httpContext">Http Context</param>
/// <param name="cacheId">Object identifier in cache - Must be unique</param>
/// <param name="getItemCallback">Callback method to fill the object</param>
/// <param name="slidingExpiration">Expiration date</param>
/// <returns>Object put in cache</returns>
public T Get<T>(string cacheId, Func<T> getItemCallback, TimeSpan? slidingExpiration = null) where T : class
{
T item = HttpRuntime.Cache.Get(cacheId) as T;
if (item == null)
{
item = getItemCallback();
if (slidingExpiration == null)
{
slidingExpiration = TimeSpan.FromSeconds(30);
}
HttpRuntime.Cache.Insert(cacheId, item, null, this.NoAbsoluteExpiration, slidingExpiration.Value);
}
return item;
}
/// <summary>
/// Retrieve the object in cache
/// If the object doesn't exist in cache or is obsolete, null is returned
/// </summary>
/// <typeparam name="T">Object Type to put or get in cache</typeparam>
/// <param name="httpContext">Http Context</param>
/// <param name="cacheId">Object identifier in cache - Must be unique</param>
/// <returns>Object put in cache</returns>
public T Get<T>(string cacheId) where T : class
{
T item = HttpRuntime.Cache.Get(cacheId) as T;
if (item == null)
{
return null;
}
return item;
}
/// <summary>
/// Delete an object using his unique id
/// </summary>
/// <param name="httpContext">Http Context</param>
/// <param name="cacheId">Object identifier in cache</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public bool Clear(string cacheId)
{
var item = HttpRuntime.Cache.Get(cacheId);
if (item != null)
{
HttpRuntime.Cache.Remove(cacheId);
return true;
}
return false;
}
/// <summary>
/// Delete all object in cache
/// </summary>
/// <param name="httpContext">Http Context</param>
public void ClearAll(string filter = null)
{
var item = HttpRuntime.Cache.GetEnumerator();
while (item.MoveNext())
{
DictionaryEntry entry = (DictionaryEntry)item.Current;
var key = entry.Key.ToString();
if (filter != null && (key.ToLower().Contains(filter.ToLower()) || filter == "*" )) //if filter, only delete if the key contains the filter value
{
HttpRuntime.Cache.Remove(entry.Key.ToString());
}
else if (filter == null) //no filter, delete everything
{
HttpRuntime.Cache.Remove(entry.Key.ToString());
}
}
}
}
Note: I didn't write this myself but can't find the original source.
This is how you use it:
// Retrieve object from cache if it exist, callback is performed to set and return object otherwise
UserObject userObject = CacheManager.Instance.Get(httpContext, "singleId", ()=> {
return new UserObject() {
Id = Guid.NewGuid()
};
});
// Retrieve object from cache if it exist, return null otherwise
UserObject userObjectRetrieved = CacheManager.Instance.Retrieve<UserObject>(httpContext, "singleId");
// Remove object from cache
CacheManager.Instance.Clear(httpContext, "singleId");
// Remove all object from cache
CacheManager.Instance.ClearAll(httpContext);
Not sure how your View design is meant to be but you could populate the printable version at the same time and hide it until the button is clicked.
Related
Overview
We use Dapper to execute stored procedures on our internal applications. I need to build out a set of APIs that we could use that sit on top of Dapper, so the enterprise can avoid being tightly coupled with dapper. I wrote the set of APIs and have them working and performing great.
A simple example of the usage is:
private async Task Delete()
{
// Get an instance of the graph builder from our factory.
IGraph graphBuilder = EntityGraphFactory.CreateEntityGraph();
// Associate the builder to a stored procedure, and map an entity instance to it.
// We provide the graph the entities primary key and value.
graphBuilder.MapToProcedure("DeleteAddress").MapEntity(this.CustomerAddress)
.DefineProperty(address => address.AddressId).IsKey();
// Get an instance of our repository and delete the entity defined in the graph.
IGraphRepository repository = GraphRepositoryFactory.CreateRepository();
await repository.DeleteAsync(graphBuilder);
this.CustomerAddress = new Address();
}
The problem
The challenge I now have is caching. I want the repository to handle the caching for us automatically. When we query for lookup data like this:
private async Task RestoreAddress()
{
IGraph graphBuilder = EntityGraphFactory.CreateEntityGraph();
IGraphRepository repository = GraphRepositoryFactory.CreateRepository();
// Map ourself to a stored procedure. Tell the graph we are going to
// take the entered Id, and pass it in to the stored procedure as a
// "AddressId" parameter.
// We then define each of the properties that the returned rows
// must map back to, renaming the columns to their associated properties.
graphBuilder.MapToProcedure("GetAddressbyId")
.MapFromEntity(this.CustomerAddress)
.DefineProperty(address => address.AddressId.ToString())
.MapToEntity<Address>()
.DefineProperty(address => address.Street == "AddressLine1")
.DefineProperty(address => address.City)
.DefineProperty(address => address.RowGuid.ToString() == "rowguid")
.DefineProperty(address => address.LastModified.ToString() == "ModifiedDate")
.DefineProperty(address => address.PostalCode)
.DefineProperty(address => address.AddressId)
.MapToEntity<StateProvince>()
.DefineProperty(province => province.StateProvinceId.ToString() == "StateProvinceId");
IEnumerable<Address> addresses = await repository.GetAsync<Address>(graphBuilder);
this.CustomerAddress = addresses.FirstOrDefault() ?? new Address();
this.SelectedProvince = this.Provinces.FirstOrDefault(
province => province.StateProvinceId == this.CustomerAddress.StateProvinceId);
}
Addresses in this example is a set of lookup data that won't change during the runtime of the app. Not until a sync is performed, at which point the cache could be cleared. The issue though is that I'm not sure how to go about caching. In this example, I am executing GetAddressById, but I could have executed GetAddressByStateId or GetAllAddresses. Then I don't know what data was already fetched and still needs to be fetched.
Potential solutions
I have a few ideas on how to go about doing this, but I'm not sure if they're going to cause conflicts or issues if I were to implement them. So before I outline them, I want to show you the implementation of the IGraph interface.
/// <summary>
/// Exposes methods for retrieving mapping information and entity definitions.
/// </summary>
internal class Graph : IGraph
{
/// <summary>
/// Initializes a new instance of the <see cref="Graph"/> class.
/// </summary>
internal Graph()
{
this.ProcedureMapping = new ProcedureBuilder(this);
this.GraphMap = new Dictionary<Type, List<PropertyDefinition>>();
}
/// <summary>
/// Gets the graph definitions created for each Type registered with it.
/// </summary>
internal Dictionary<Type, List<PropertyDefinition>> GraphMap { get; private set; }
/// <summary>
/// Gets or sets the key used by the graph as it's Primary Key.
/// </summary>
internal PropertyDefinition RootKey { get; set; }
/// <summary>
/// Gets the procedure mapping.
/// </summary>
internal ProcedureBuilder ProcedureMapping { get; private set; }
/// <summary>
/// Gets the graph generated for the given entity
/// </summary>
/// <typeparam name="TEntity">The entity type to retrieve definition information from.</typeparam>
/// <returns>
/// Returns a collection of PropertyDefinition objects
/// </returns>
public IEnumerable<PropertyDefinition> GetEntityGraph<TEntity>() where TEntity : class, new()
{
return this.GetEntityGraph(typeof(TEntity));
}
/// <summary>
/// Gets a collection of PropertyDefinition objects that make up the data graph for the Entity speified.
/// </summary>
/// <param name="entityType">The entity type to retrieve definition information from.</param>
/// <returns>
/// Returns a collection of PropertyDefinition objects
/// </returns>
public IEnumerable<PropertyDefinition> GetEntityGraph(Type entityType)
{
if (GraphMap.ContainsKey(entityType))
{
return GraphMap[entityType];
}
return Enumerable.Empty<PropertyDefinition>();
}
/// <summary>
/// Gets the graph generated by the graph for all entities graphed on it.
/// </summary>
/// <returns>
/// Returns a dictionary where the key is a mapped type and the value is its definition data.
/// </returns>
public Dictionary<Type, IEnumerable<PropertyDefinition>> GetBuilderGraph()
{
// Return a new dictionary containing the same values. This prevents someone from adding content to the
// dictionary we hold internally.
return this.GraphMap.ToDictionary(keySelector => keySelector.Key, valueSelector => valueSelector.Value as IEnumerable<PropertyDefinition>);
}
/// <summary>
/// Resets the graph so that it may be used in a fresh state.
/// </summary>
public void ClearGraph()
{
this.GraphMap.Clear();
this.RootKey = null;
this.ProcedureMapping = new ProcedureBuilder(this);
}
/// <summary>
/// Gets the primary key defined for this data graph.
/// </summary>
/// <returns>Returns the PropertyDefinition associated as the Builder Key.</returns>
public PropertyDefinition GetKey()
{
return this.RootKey;
}
/// <summary>
/// Gets the stored procedure for the operation type provided.
/// </summary>
/// <param name="operationType">Type of operation the procedure will perform when executed.</param>
/// <returns>
/// Returns the ProcedureDefinition mapped to this graph for the given operation type.
/// </returns>
public ProcedureDefinition GetProcedureForOperation(ProcedureOperationType operationType)
{
string procedureName = this.ProcedureMapping.ProcedureMap[operationType];
return new ProcedureDefinition(operationType, procedureName);
}
/// <summary>
/// Gets all of the associated stored procedure mappings.
/// </summary>
/// <returns>
/// Returns a collection of ProcedureDefinition objects mapped to this data graph.
/// </returns>
public IEnumerable<ProcedureDefinition> GetProcedureMappings()
{
// Convert the builders dictionary mapping of stored procedures to OperationType into a collection of ProcedureDefinition objects.
return this.ProcedureMapping.ProcedureMap
.Where(kvPair => !string.IsNullOrEmpty(kvPair.Value))
.Select(kvPair => new ProcedureDefinition(kvPair.Key, kvPair.Value));
}
/// <summary>
/// Maps the data defined in this graph to a stored procedure.
/// </summary>
/// <param name="procedureName">Name of the procedure responsible for receiving the data in this graph.</param>
/// <returns>
/// Returns the data graph.
/// </returns>
public IGraph MapToProcedure(string procedureName)
{
this.ProcedureMapping.DefineForAllOperations(procedureName);
return this;
}
/// <summary>
/// Allows for mapping the data in this graph to different stored procedures.
/// </summary>
/// <returns>
/// Returns an instance of IProcedureBuilder used to perform the mapping operation
/// </returns>
public IProcedureBuilder MapToProcedure()
{
return this.ProcedureMapping;
}
/// <summary>
/// Defines what Entity will be used to building out property definitions
/// </summary>
/// <typeparam name="TEntity">The type of the entity to use during the building process.</typeparam>
/// <returns>
/// Returns an instance of IEntityDefinition that can be used for building out the entity definition
/// </returns>
public IPropertyBuilderForInput<TEntity> MapFromEntity<TEntity>() where TEntity : class, new()
{
this.CreateDefinition<TEntity>();
return new PropertyBuilder<TEntity>(this, DefinitionDirection.In);
}
/// <summary>
/// Defines what Entity will be used to building out property definitions
/// </summary>
/// <typeparam name="TEntity">The type of the entity to use during the building process.</typeparam>
/// <param name="entity">An existing instance of the entity used during the building process.</param>
/// <returns>
/// Returns an instance of IEntityDefinition that can be used for building out the entity definition
/// </returns>
public IPropertyBuilderForInput<TEntity> MapFromEntity<TEntity>(TEntity entity) where TEntity : class, new()
{
this.CreateDefinition<TEntity>();
return new PropertyBuilder<TEntity>(this, DefinitionDirection.In, entity);
}
public IPropertyBuilderForOutput<TEntity> MapToEntity<TEntity>() where TEntity : class, new()
{
this.CreateDefinition<TEntity>();
return new PropertyBuilder<TEntity>(this, DefinitionDirection.Out);
}
public IPropertyBuilderForInput<TEntity> MapEntity<TEntity>() where TEntity : class, new()
{
this.CreateDefinition<TEntity>();
return new PropertyBuilder<TEntity>(this, DefinitionDirection.Both);
}
public IPropertyBuilderForInput<TEntity> MapEntity<TEntity>(TEntity entity) where TEntity : class, new()
{
this.CreateDefinition<TEntity>();
return new PropertyBuilder<TEntity>(this, DefinitionDirection.Both, entity);
}
private void CreateDefinition<TEntity>() where TEntity : class, new()
{
// A definition has already been created, so return.
if (this.GraphMap.ContainsKey(typeof(TEntity)))
{
return;
}
this.GraphMap.Add(typeof(TEntity), new List<PropertyDefinition>());
}
}
The point of this class is to let you map a Type to it, and then use interfaces that are returned on the MapEntity methods, to define properties and their characteristics. The repository then is given the builder, and pulls the Mappings from it, generating a Dapper DynamicParameters collection from it. The map is also used in a custom Dapper TypeMapper.
Since I am only caching things that are queried, I'll save some page-space and just share the query method on my repository, and its TypeMapper.
public async Task<IEnumerable<TEntity>> GetAsync<TEntity>(IGraph builder, IDataContext context = null)
{
IEnumerable<TEntity> items = null;
DynamicParameters parameters = this.GetParametersFromDefinition(builder, DefinitionDirection.In);
// Setup our mapping of the return results.
this.SetupSqlMapper<TEntity>(builder);
ProcedureDefinition mapping = builder.GetProcedureForOperation(ProcedureOperationType.Select);
// Query the database
await this.SetupConnection(
context,
async (connection, transaction) => items = await connection.QueryAsync<TEntity>(
mapping.StoredProcedure,
parameters,
commandType: CommandType.StoredProcedure,
transaction: transaction));
return items;
}
private async Task SetupConnection(IDataContext context, Func<IDbConnection, IDbTransaction, Task> communicateWithDatabase)
{
SqlDataContext connectionContext = await this.CreateConnectionContext(context);
IDbConnection databaseConnection = await connectionContext.GetConnection();
// Fetch the transaction, if any, associated with the context. If none exists, null is returned and passed
// in to the ExecuteAsync method.
IDbTransaction transaction = connectionContext.GetTransaction();
try
{
await communicateWithDatabase(databaseConnection, transaction);
}
catch (Exception)
{
this.RollbackChanges(connectionContext);
throw;
}
// If we are given a shared connection, we are not responsible for closing it.
if (context == null)
{
this.CloseConnection(connectionContext);
}
}
private DynamicParameters GetParametersFromDefinition(IGraph builder, DefinitionDirection direction)
{
// Fetch the model definition, then loop through each property we are saving and add it
// do a Dapper DynamicParameer dictionary.
Dictionary<Type, IEnumerable<PropertyDefinition>> definition = builder.GetBuilderGraph();
var parameters = new DynamicParameters();
foreach (var pair in definition)
{
IEnumerable<PropertyDefinition> properties =
pair.Value.Where(property => property.Direction == direction || property.Direction == DefinitionDirection.Both);
foreach (PropertyDefinition data in properties)
{
parameters.Add(data.ResolvedName, data.PropertyValue);
}
}
return parameters;
}
/// <summary>
/// Sets up the Dapper SQL Type mapper.
/// </summary>
/// <param name="type">The type we want to map the build definition to.</param>
/// <param name="graph">The graph.</param>
private void SetupSqlMapper(Type type, IGraph builder)
{
SqlMapper.SetTypeMap(
type,
new CustomPropertyTypeMap(type, (typeToMap, columnName) =>
{
// Grab all of the property definitions on the entity defined with the IGraph
IEnumerable<PropertyDefinition> entityDefinition = builder.GetEntityGraph(typeToMap);
PropertyInfo propertyForColumn;
// Lookup a PropertyDefinition definition from the IGraph that can map to the columnName provided by the database.
PropertyDefinition propertyData = null;
if (this.dataStoreConfig.EnableSensitiveCasing)
{
propertyData = entityDefinition.FirstOrDefault(
definition => definition.ResolvedName.Equals(columnName) || definition.Property.Name.Equals(columnName));
}
else
{
propertyData = entityDefinition.FirstOrDefault(
definition =>
definition.ResolvedName.ToLower().Equals(columnName.ToLower()) ||
definition.Property.Name.ToLower().Equals(columnName.ToLower()));
}
// If a mapping definition was not found, use the TypePool to fetch the property info from the type cache.
// Otherwise we assign the property from the definition mapping.
if (propertyData == null)
{
propertyForColumn = this.dataStoreConfig.EnableSensitiveCasing
? TypePool.GetProperty(typeToMap, (info) => info.Name.Equals(columnName))
: TypePool.GetProperty(typeToMap, (info) => info.Name.ToLower().Equals(columnName.ToLower()));
}
else
{
propertyForColumn = propertyData.Property;
}
if (propertyForColumn == null)
{
Debug.WriteLine(string.Format("The column {0} could not be mapped to the Type {1}. It does not have a definition associated with the data graph, nor a property with a matching name.", columnName, typeToMap.Name));
}
return propertyForColumn;
}));
}
There are a couple different paths I'm considering here.
Override GetHashCode() on my IGraph implementation and have it return a hashed value of the Dictionary & RootKey properties. Then in the repository, I ask for the graphs hashcode, query the database and cache the return results in a Dictionary of <HashCode, ResultSet>. The next time I create the builder, or re-use an existing one, the repository could do a key lookup and return back the cache.
In this approach, is that safe? Can I call GraphMap.GethashCode() and rest assured that the hash will be based on the contents of the dictionary, and therefore (mostly)unique? Would I have to iterate over each item in the dictionary, asking for HashCodes on their members to prevent hash code collisions?
Cache the expression used to generate the map. Within my repository, I can generate a hash, based on the hashcode of each expression used on the builder. This way, if you ever use the same series of expressions to build the mapping, the repository would know and could return the previously fetched data?
Are hashcodes a safe way to go, or should I be exploring different routes? Is there an industry standard way of going about this?
I'm trying to create a linked list for my personal library that can handle EVERYTHING. I'm trying to write it so that it can 'equally' easily hand int, null,DateTime or Class and I wanted it to be easily extendable, so that if I wanted to quickly make stack out of it, I can just write push, pop, and peek methods and so forth.
Currently, my code looks like this. Note that I use 'Base' as my generic type.
namespace ClassLibrary1
{
public class LinkedList<Base> where Base : class
{
public class Node
{
private Node next;
private Node prev;
private Base value;
/// <summary>
/// Constructor for Nodes of Circular Linked List class.
/// Calls overloaded constructor for no previous or next provided.
/// O(1)
/// </summary>
/// <param name="value">The value to be stored. Can use tuple for associations</param>
public Node(Base value)
{
new Node(null, null, value);
}
/// <summary>
/// Constructor for nodes of Circular Linked List class.
/// O(1)
/// </summary>
/// <param name="prev">The previous node in the linked list</param>
/// <param name="next">The next node in the linked list</param>
/// <param name="value">The value to be stored</param>
public Node(Node prev, Node next, Base value)
{
this.prev = prev;
this.next = next;
this.value = value;
}
/// <summary>
/// Sets the 'next' attribute of the node to the passed value.
/// O(1)
/// Chainable
/// </summary>
/// <param name="next">The new value of the 'next' attribute.</param>
/// <returns>Chainable(Node, this)</returns>
public Node setNext(Node next)
{
this.next = next;
return this;
}
/// <summary>
/// Sets the 'prev' attribute of the node to the passed value
/// O(1)
/// Chainable
/// </summary>
/// <param name="prev">The new value of the 'prev' attribute to denote the previous node</param>
/// <returns>Chainable(Node, this)</returns>
public Node setPrev(Node prev)
{
this.prev = prev;
return this;
}
/// <summary>
/// Changes the stored value of type Base to the passed value.
/// O(1)
/// Chainable
/// </summary>
/// <param name="value">The new value to be stored with the node</param>
/// <returns>Chainable(Node, this)</returns>
public Node setVal(Base value)
{
this.value = value;
return this;
}
/// <summary>
/// Returns the next node in the linked list.
/// O(1)
/// </summary>
/// <returns>The next node in the linked list.(Node)</returns>
public Node getNext()
{
return this.next;
}
/// <summary>
/// Returns the previous node in the linked list.
/// O(1)
/// </summary>
/// <returns>The previous node in the linked list.(Node)</returns>
public Node getPrev()
{
return this.prev;
}
/// <summary>
/// Returns the value stored at this node.
/// O(1)
/// </summary>
/// <returns>The value stored at this node.(Base)</returns>
public Base getVal()
{
return this.value;
}
}
public Node head;
public bool duplicates;
public bool hasNullValues;
public bool throwNullError;
/// <summary>
/// Constructor for the LinkedList. Creates a null head node.
/// Duplication defaulted to false
/// O(1)
/// </summary>
public LinkedList()
{
this.head = new Node(null);
this.head.setNext(this.head).setPrev(this.head);
this.duplicates = false;
this.hasNullValues = false;
this.throwNullError = false;
}
/// <summary>
/// Allows duplication for the linked list.
/// O(1)
/// Chainable attribute.
/// </summary>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> hasDuplicates()
{
this.duplicates = true;
return this;
}
/// <summary>
/// Allows the structure to store null values in nodes.
/// O(1)
/// Chainable.
/// </summary>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> hasNulls()
{
this.hasNullValues = true;
return this;
}
/// <summary>
/// Causes the structure to throw a null error when a null value is inserted.
/// If hasNulls is off, turns it on.
/// O(1)
/// Chainable.
/// </summary>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> throwsNulls()
{
if (!this.hasNullValues)
{
this.hasNullValues = true;
}
this.throwNullError = true;
return this;
}
/// <summary>
/// Iff duplicates not allowed, searches for value in list. Throws error if duplicate found.
/// Creates a new node at the end of the list, then links it to the head node.
/// O(length) [if hasDuplicates()]
/// O(1) [if else]
/// Chainable
/// </summary>
/// <param name="value">Value stored at the new node in the list</param>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> add(Base value)
{
if (!duplicates)
{
if (search(value) != null)
{
throw new Exception("Value already exists in the linked list.");
}
}
if (!this.hasNullValues && value != null)
{
if (this.throwNullError)
{
throw new Exception("Cannot insert null values");
}
else
{
return this;
}
}
Node newNode = new Node(value);
this.head.getPrev().setNext(newNode);
this.head.setPrev(newNode);
return this;
}
/// <summary>
/// Iterates through the list until first such node for with a matching value is found.
/// Returns null if no matches found.
/// Use searchAll to find duplicates.
/// O(length)
/// </summary>
/// <param name="value">The value to be searched for.</param>
/// <returns>First node with the desired value(Node?)</returns>
public Node search(Base value)
{
Node temp = this.head.getNext();
while (!temp.getVal().Equals(value))
{
if (temp.Equals(this.head))
{
return null;
}
temp = temp.getNext();
}
return temp;
}
/// <summary>
/// If value doesn't exist in the list, throws an exception.
/// Deletes the first node found with the chosen value.
/// Use DeleteAll to delete all instances.
/// Chainable.
/// O(length)
/// </summary>
/// <param name="value">Value to be removed from the list.</param>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> delete(Base value)
{
try{
return delete(search(value));
}
catch(Exception e){
throw new Exception("Node to be deleted not found");
}
}
/// <summary>
/// Removes all pointers to the passed node.
/// O(1)
/// </summary>
/// <param name="tbd">The node to be deleted.</param>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> delete(Node tbd)
{
if (tbd.Equals(this.head))
{
throw new Exception("Cannot delete head node");
}
else
{
tbd.getPrev().setNext(tbd.getNext());
tbd.getNext().setPrev(tbd.getPrev());
}
return this;
}
/// <summary>
/// Returns a LinkedList of all nodes containing the desired value.
/// O(length)
/// </summary>
/// <param name="value">The value to be found.</param>
/// <returns>A LinkedList of Nodes with matching values.(LinkedList<Node>)</returns>
public LinkedList<Node> searchAll(Base value)
{
LinkedList<Node> returnList = new LinkedList<Node>();
Node temp = this.head.getNext();
while (!temp.Equals(this.head))
{
if (temp.getVal().Equals(value))
{
returnList.add(temp);
}
temp = temp.getNext();
}
return returnList;
}
/// <summary>
/// Returns the first Node in the Linked List.
/// O()
/// </summary>
/// <returns>First non-head node in the list.(Node)</returns>
public Node firstOrDefault()
{
return this.head.getNext();
}
/// <summary>
/// Returns the value of the first node in the list.
/// O(1)
/// </summary>
/// <returns>FIrst non-head </returns>
public Base firstVal()
{
return this.head.getNext().getVal();
}
/// <summary>
/// Gets the last node in the linked list.
/// O(1)
/// </summary>
/// <returns>The last node in the linked list.(Node)</returns>
public Node tail()
{
return this.head.getPrev();
}
/// <summary>
/// Returns the value of the last node in the linked list.
/// O(1)
/// </summary>
/// <returns>VThe value of the tail node.(Base)</returns>
public Base tailVal()
{
return this.head.getPrev().getVal();
}
public static void Main()
{
LinkedLis t<Int32> mine = new LinkedList<Int32>();
}
}
}
However, it gives Red Text under the Int32, saying "The type 'int' must be a reference type in order to use it as a parameter 'Base' in the generic type or method ---this---.
Tell me if you would like me to remove the comments, I'm not sure if that makes it harder or easier to solve.
Because you declared a constraint on a Base type to be a class (a reference type):
public class LinkedList<Base> where Base : class
It exactly forbids using Int32, because it's a value type and is different from a required reference type.
new LinkedList<Int32>()
So, to fix this particular problem, you would need to to create a wrapper class for your integer values.
Before you do this though, check your intentions to store any type in your linked list. Doing so you will strip you off all advantages of C# as a strongly typed language.
And as it was mentioned before, unless you write this code as a pure academic exercise, you should use an existing .NET LinkedList and possibly extend/inherit it, if you need more functionality.
Update: I assumed it went without saying, but to make it crystal clear don't forget that Nullable is a struct, not a class, so you cannot use "cheats" like int?.
This question already has answers here:
ASP.NET cache add vs insert
(3 answers)
Closed 9 years ago.
I know the difference between Cache.Insert and Cache.Add, but what about Cache["Key"] = "Value"?
According to the documentation of the Cache.Item property, there is no difference:
REMARKS:
You can use this property to retrieve the value of a specified cache item, or to add an item and a key for it to the cache. Adding a cache item using the Item property is equivalent to calling the Cache.Insert method.
(emphasis is mine).
Here is an example of writing a very simple wrapper (in response to comment Is there any difference between Cache.Insert("Key", "Value") and Cache["Key"] = "Value"?) for setting the defaults when adding items to the cache using the index methods. This is very basic.
public class CacheHandler
{
/// <summary>
/// static cache dependencies
/// </summary>
readonly static CacheDependency dependecies = null;
/// <summary>
/// sliding expiration
/// </summary>
readonly static TimeSpan slidingExpiration = TimeSpan.FromMinutes(5);
/// <summary>
/// absolute expiration
/// </summary>
readonly static DateTime absoluteExpiration = System.Web.Caching.Cache.NoAbsoluteExpiration;
/// <summary>
/// private singleton
/// </summary>
static CacheHandler handler;
/// <summary>
/// gets the current cache handler
/// </summary>
public static CacheHandler Current { get { return handler ?? (handler = new CacheHandler()); } }
/// <summary>
/// private constructor
/// </summary>
private CacheHandler() { }
/// <summary>
/// Gets \ Sets objects from the cache. Setting the object will use the default settings above
/// </summary>
/// <param name="key">the cache key</param>
/// <returns>the object stored in the cache</returns>
public object this[string key]
{
get
{
if (HttpContext.Current == null)
throw new Exception("The current HTTP context is unavailable. Unable to read cached objects.");
return HttpContext.Current.Cache[key];
}
set
{
if (HttpContext.Current == null)
throw new Exception("The current HTTP context is unavailable. Unable to set the cache object.");
HttpContext.Current.Cache.Insert(key, value, dependecies, absoluteExpiration , slidingExpiration);
}
}
/// <summary>
/// the current HTTP context
/// </summary>
public Cache Context
{
get
{
if (HttpContext.Current == null)
throw new Exception("The current HTTP context is unavailable. Unable to retrive the cache context.");
return HttpContext.Current.Cache;
}
}
}
Again this is super simple and basic but requires a call to another service to insert the cache something like.
protected void Page_Load(object sender, EventArgs e)
{
CacheHandler.Current["abc"] = "123";
}
If you are just starting your application you could replace the Cache property of an ASP.Net page with your new cache handler such as.
public partial class BasePage : Page
{
protected new CacheHandler Cache
{
get { return CacheHandler.Current; }
}
}
Then all your pages can be changed to the following.
public partial class _Default : **BasePage**
{
}
And calling the cache handler is a simple as
protected void Page_Load(object sender, EventArgs e)
{
Cache["abc"] = "123";
}
Which will be your cache handler instead of the default Cache object.
These are just options and really up to you how you wish to handle your caching within your application and if this is really worth the effort.
Cheers.
I have 3 entities.
Let's say I have Event entity, and 2 "derived" entities: Accident, Repair.
They provide some additional fields over Event entity.
Event have StartDate and EndDate which are always required so I mark them with [Required] attribute. That's ok. But I have some additional validation logic that checks if the Event is Repair, then some other Event fields are also required. For this I provide custom validator.
The problem is that the properties marked with [Required] attribute are always checked before other validators.
What I want achieve:
If Event is Accident I want to make Event.SomeField required.
Validation summary should show now contain 3 validation errors at the very first validation attempt.
How it behaves now:
If Event is Accident first validation attempt shows 2 errors of 2 properties marked as [Required]. Only after I fill those, on the next validation attempt fires my custom validator which also states that 3rd Event.SomeField is also required.
I want all the required fields to validate at the same time.
Is this possible? How to achieve this?
For the case that a property is required based on a certain condition, i use a custom attribute, that was initially provided by Jeff Handley in his blog.
Here´s the code of the Attribute:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true)]
public class ConditionallyRequiredAttribute : RequiredAttribute {
private MemberInfo _member;
/// <summary>
/// The name of the member that will return the state that indicates
/// whether or not the validated member is required.
/// </summary>
public string ConditionMember { get; private set; }
/// <summary>
/// The condition value under which this validator treats
/// the affected member as required.
/// </summary>
public object RequiredCondition { get; private set; }
/// <summary>
/// Comma-separated list of additional members to
/// add to validation errors. By default, the
/// <see cref="ConditionMember"/> is added.
/// </summary>
public string ErrorMembers { get; set; }
/// <summary>
/// Conditionally require a value, only when the specified
/// <paramref name="conditionMember"/> is <c>true</c>.
/// </summary>
/// <param name="conditionMember">
/// The member that must be <c>true</c> to require a value.
/// </param>
public ConditionallyRequiredAttribute(string conditionMember)
: this(conditionMember, true) { }
/// <summary>
/// Conditionally require a value, only when the specified
/// <paramref name="conditionMember"/> has a value that
/// exactly matches the <paramref name="requiredCondition"/>.
/// </summary>
/// <param name="conditionMember">
/// The member that will be evaluated to require a value.
/// </param>
/// <param name="requiredCondition">
/// The value the <paramref name="conditionMember"/> must
/// hold to require a value.
/// </param>
public ConditionallyRequiredAttribute(string conditionMember, object requiredCondition) {
this.ConditionMember = conditionMember;
this.RequiredCondition = requiredCondition;
this.ErrorMembers = this.ConditionMember;
}
/// <summary>
/// Override the base validation to only perform validation when the required
/// condition has been met. In the case of validation failure, augment the
/// validation result with the <see cref="ErrorMembers"/> as an additional
/// member names, as needed.
/// </summary>
/// <param name="value">The value being validated.</param>
/// <param name="validationContext">The validation context being used.</param>
/// <returns>
/// <see cref="ValidationResult.Success"/> if not currently required or if satisfied,
/// or a <see cref="ValidationResult"/> in the case of failure.
/// </returns>
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
if (this.DiscoverMember(validationContext.ObjectType)) {
object state = this.InvokeMember(validationContext.ObjectInstance);
// We are only required if the current state
// matches the specified condition.
if (Object.Equals(state, this.RequiredCondition)) {
ValidationResult result = base.IsValid(value, validationContext);
if (result != ValidationResult.Success && this.ErrorMembers != null && this.ErrorMembers.Any()) {
result = new ValidationResult(result.ErrorMessage,
result.MemberNames.Union(this.ErrorMembers.Split(',').Select(s => s.Trim())));
}
return result;
}
return ValidationResult.Success;
}
throw new InvalidOperationException(
"ConditionallyRequiredAttribute could not discover member: " + this.ConditionMember);
}
/// <summary>
/// Discover the member that we will evaluate for checking our condition.
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
private bool DiscoverMember(Type objectType) {
if (this._member == null) {
this._member = (from member in objectType.GetMember(this.ConditionMember).Cast<MemberInfo>()
where IsSupportedProperty(member) || IsSupportedMethod(member)
select member).SingleOrDefault();
}
// If we didn't find 1 exact match, indicate that we could not discover the member
return this._member != null;
}
/// <summary>
/// Determine if a <paramref name="member"/> is a
/// method that accepts no parameters.
/// </summary>
/// <param name="member">The member to check.</param>
/// <returns>
/// <c>true</c> if the member is a parameterless method.
/// Otherwise, <c>false</c>.
/// </returns>
private bool IsSupportedMethod(MemberInfo member) {
if (member.MemberType != MemberTypes.Method) {
return false;
}
MethodInfo method = (MethodInfo)member;
return method.GetParameters().Length == 0
&& method.GetGenericArguments().Length == 0
&& method.ReturnType != typeof(void);
}
/// <summary>
/// Determine if a <paramref name="member"/> is a
/// property that has no indexer.
/// </summary>
/// <param name="member">The member to check.</param>
/// <returns>
/// <c>true</c> if the member is a non-indexed property.
/// Otherwise, <c>false</c>.
/// </returns>
private bool IsSupportedProperty(MemberInfo member) {
if (member.MemberType != MemberTypes.Property) {
return false;
}
PropertyInfo property = (PropertyInfo)member;
return property.GetIndexParameters().Length == 0;
}
/// <summary>
/// Invoke the member and return its value.
/// </summary>
/// <param name="objectInstance">The object to invoke against.</param>
/// <returns>The member's return value.</returns>
private object InvokeMember(object objectInstance) {
if (this._member.MemberType == MemberTypes.Method) {
MethodInfo method = (MethodInfo)this._member;
return method.Invoke(objectInstance, null);
}
PropertyInfo property = (PropertyInfo)this._member;
return property.GetValue(objectInstance, null);
}
#if !SILVERLIGHT
/// <summary>
/// The desktop framework has this property and it must be
/// overridden when allowing multiple attributes, so that
/// attribute instances can be disambiguated based on
/// field values.
/// </summary>
public override object TypeId {
get { return this; }
}
#endif
}
Here´s an example:
public class Dummy{
public bool IsCondition {get; set;}
[ConditionallyRequired("IsCondition", true)]
public string SometimesRequired {get; set;}
}
I need to fill some dropdown boxex from some reference data. i.e City List, Country List etc. I need to fill it in various webforms. I think, we should cache this data in our application so that, we don't hit database on every form. I am new to caching and ASP.Net. Please suggest me how to do this.
I always add the following class to all my projects which give me easy access to the Cache object. Implementing this, following Hasan Khan's answer would be a good way to go.
public static class CacheHelper
{
/// <summary>
/// Insert value into the cache using
/// appropriate name/value pairs
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="o">Item to be cached</param>
/// <param name="key">Name of item</param>
public static void Add<T>(T o, string key, double Timeout)
{
HttpContext.Current.Cache.Insert(
key,
o,
null,
DateTime.Now.AddMinutes(Timeout),
System.Web.Caching.Cache.NoSlidingExpiration);
}
/// <summary>
/// Remove item from cache
/// </summary>
/// <param name="key">Name of cached item</param>
public static void Clear(string key)
{
HttpContext.Current.Cache.Remove(key);
}
/// <summary>
/// Check for item in cache
/// </summary>
/// <param name="key">Name of cached item</param>
/// <returns></returns>
public static bool Exists(string key)
{
return HttpContext.Current.Cache[key] != null;
}
/// <summary>
/// Retrieve cached item
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Name of cached item</param>
/// <param name="value">Cached value. Default(T) if item doesn't exist.</param>
/// <returns>Cached item as type</returns>
public static bool Get<T>(string key, out T value)
{
try
{
if (!Exists(key))
{
value = default(T);
return false;
}
value = (T)HttpContext.Current.Cache[key];
}
catch
{
value = default(T);
return false;
}
return true;
}
}
From other question of yours I read that you're using 3 layer architecture with dal, business and presentation layer.
So I assume that you have some data access class. Ideal thing to do would be to have a cached implementation of the same class and do caching in that.
Eg: If you have an interface IUserRepository then UserRepository class would implement it and add/delete/update entries in db via methods then you can also have CachedUserRepository which will contain instance of UserRepository object and on get methods it will first look into the cache against some key (derived from method parameters) and if the item is found then it will return it otherwise you call the method on internal object; get the data; add to cache and then return it.
Your CachedUserRepository will also have instance of cache object obviously. You can look at http://msdn.microsoft.com/en-us/library/18c1wd61(v=vs.85).aspx for details on how to use Cache object.