SQLite Implementation in VS 2019 - c#

I'm still really new to coding and trying to make my first WPF application. I have been trying to implement sqlite for the past like 3 days now.
I am using VS 2019. I have downloaded the SQLite Toolbox and am following the instructions here - https://github.com/ErikEJ/SqlCeToolbox/wiki/EF6-workflow-with-SQLite-DDEX-provider. I did a full installation. Was I supposed to install it in my project directory? Because now I just have a bunch of files and nothing seems to have changed in Studio. I tried using Install.exe, but it returned a "confirm option not enabled" error. Looking at a similar question, I tried putting the files in an external folder in my project, and then installed the System.Data.SQLite.EF6.dll to my GAC using the VS Dev Console. The toolbox doesn't see any changes, and does not recognize the dll and I'm having a hard time finding reliable information for my version. Thanks for any help getting pointed in the right direction!

I'm not sure why you mention toolbox as far as I'm aware you access the SQLite functionality programmatically.
The NuGet packages that I recently used for a Xamarin project (SQLite-net-pcl by Frank Krueger and supporting libraries) allowed me to use pretty simple object mapping without recourse to SQL like strings.
I use a lot of interfaces in my code, but here's my all access database class
:
public class AllAccessDataTableBaseSqLite<T> : IDataAccessRead<T>, IDataAccessWrite<T>,IDataAccessExpressionSearch<T>, IDataAccessDelete<T> where T: IDataRecord, new()
{
//Note that this static value will only apply to those classes based on the same generic type e.g. all DataTableBase<User> instances etc.
public static SQLiteAsyncConnection DBConnection;
/// <summary>
/// Lock object to prevent multi-thread interruption of code segment.
/// </summary>
public static readonly object CollisionLock = new object();
/// <summary>
/// Constructor
/// </summary>
public AllAccessDataTableBaseSqLite()
{
lock (CollisionLock)
{
if (DBConnection != null)
{
DBConnection.CreateTableAsync<T>().Wait();
return;
}
try
{
string directory;
if (DeviceInfo.Platform != DevicePlatform.Unknown)
{
directory = FileSystem.AppDataDirectory;
}
else
{
directory = "DataStore";
var directoryInfo = Directory.CreateDirectory(directory);
directory = directoryInfo.FullName;
}
var path = Path.Combine(directory, $"{typeof(T).Name}.db");
if (!File.Exists(path))
{
using var fileStream = File.Create(path);
fileStream.Close();
}
DBConnection = new SQLiteAsyncConnection(path);
DBConnection.CreateTableAsync<T>().Wait();
}
catch (Exception ex)
{
if (ex is UnauthorizedAccessException)
{
}
}
}
}
/// <summary>
/// Create the data table
/// </summary>
/// <returns></returns>
public async Task<CreateTableResult> CreateTableAsync()
{
if (DBConnection != null)
{
return await DBConnection.CreateTableAsync<T>();
}
return CreateTableResult.Migrated;
}
/// <summary>
/// Create a new record entry
/// </summary>
/// <param name="entity">Data entity to enter</param>
/// <param name="user">Current User information</param>
/// <returns>New entry record if successful</returns>
public async Task<T> CreateAsync(T entity, IUserRecord user)
{
if (entity == null)
{
return default(T);
}
if (DBConnection == null)
{
return default(T);
}
entity.CreatedDate = DateTime.UtcNow;
entity.CreatedByUserId = user.Id;
entity.Id = 0;
try
{
await DBConnection.InsertAsync(entity);
}
catch (SQLiteException e)
{
if (e.Message == "Constraint")
{
throw new InvalidConstraintException(e.Message, e.InnerException);
}
}
var result = entity;
return result;
}
/// <summary>
/// Update a collection of new entities of type T to the data table.
/// All entities should be present within the data table
/// </summary>
/// <param name="entityList">Entity collection</param>
/// <param name="user">user making the change</param>
/// <returns>ID of entities successfully updated or added</returns>
public async Task<int> UpdateAllAsync(IEnumerable<T> entityList, IUserRecord user)
{
var result = 0;
foreach (var t in entityList)
{
if (null != await UpdateAsync(t, user))
{
result++ ;
}
}
return result;
}
/// <summary>
/// Obtain the data record with the given Id
/// </summary>
/// <param name="id">Id value to select the record by</param>
/// <returns>A valid record if found otherwise null</returns>
public async Task<T> GetById(int id)
{
if (DBConnection == null)
{
return default(T);
}
return await DBConnection.Table<T>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
/// <summary>
/// This function returns all database entries that are not marked deleted or changed
/// Warning: The data set may be very large
/// </summary>
/// <returns>A list of entries</returns>
public async Task<List<T>> GetAll()
{
if (DBConnection != null)
{
return await DBConnection.Table<T>().Where(x=>x.ChangedDate==default && x.DeletedDate==default)
.ToListAsync();
}
return new List<T>();
}
/// <inheritdoc />
public async Task<List<T>> GetAllHistoric() => await DBConnection.Table<T>().ToListAsync();
/// <summary>
/// This function is used to update the supplied record entry within the database.
/// If the supplied record does not have a non-zero value Id field it is assumed to be a
/// new record to be inserted into the database.
/// </summary>
/// <param name="entity">Record to update</param>
/// <param name="user">User performing the action</param>
/// <returns></returns>
public async Task<T> UpdateAsync(T entity, IUserRecord user)
{
if (DBConnection == null)
{
return default(T);
}
if (entity == null)
{
return default(T);
}
var newRecord = (T) ((entity) as BaseRecord<T>)?.Clone();
if (null == newRecord)
{
return default(T);
}
//if Id is zero assume that the record is new and to be added
if (newRecord.Id == 0)
{
if (user != null)
{
newRecord.CreatedByUserId = user.Id;
}
newRecord.CreatedDate = DateTime.UtcNow;
newRecord.Id = await DBConnection.InsertAsync(newRecord);
return newRecord;
}
// Id is not zero and thus a new record should be created linked to the old record.
var oldRecord = await GetById(newRecord.Id);
oldRecord.ChangedDate = DateTime.UtcNow;
if (user != null)
{
oldRecord.ChangedByUserId = user.Id;
}
try
{
var result = await DBConnection.UpdateAsync(oldRecord);
}
catch (Exception e)
{
Debug.WriteLine($"UpdateAsync {e.Message}");
}
newRecord.PreviousRecordId = oldRecord.Id;
newRecord.Id = 0;
return await CreateAsync(newRecord, user);
}
/// <inheritdoc />
public async Task<int> DeleteAsync(T entity)
{
if (DBConnection == null)
{
return -1;
}
return await DBConnection.DeleteAsync(entity);
}
/// <inheritdoc />
public async Task DeleteAll()
{
await DBConnection.DropTableAsync<T>();
await CreateTableAsync();
}
/// <inheritdoc />
public async Task<PagedResult<T>> GetAllPagedResult(int recordId, uint maxResults = 100)
{
if (DBConnection == null)
{
return null;
}
List<T> list;
if (maxResults == 0)
{
list = await GetAll();
}
else
{
list = await DBConnection.Table<T>().Where(x => (x.Id >= recordId && x.ChangedDate == default && x.DeletedDate == default)).ToListAsync();
if (list.Count() > maxResults)
{
list = list.GetRange(0, (int) maxResults);
}
}
return new PagedResult<T>(list, list.Count());
}
/// <inheritdoc />
public async Task<IEnumerable<T>> FindAsyncOrdered<TValue>(Expression<Func<T, bool>> predicate = null,
Expression<Func<T, TValue>> orderBy = null)
{
var query = DBConnection.Table<T>();
if (predicate != null)
{
query = query.Where(predicate);
}
if (orderBy != null)
{
query = query.OrderBy<TValue>(orderBy);
}
return await query.ToListAsync();
}
/// <inheritdoc />
public async Task<T> FindFirst(Expression<Func<T, bool>> predicate) => await DBConnection.FindAsync(predicate);
}
I'm using data classes based upon:
public interface IDataRecord
{
/// <summary>
/// Identifier for record
/// </summary>
int Id { get; set; }
/// <summary>
/// Link to previous version of record
/// </summary>
int PreviousRecordId { get; set; }
/// <summary>
/// User Identity that made the change
/// </summary>
int ChangedByUserId { get; set; }
/// <summary>
/// Date when the data record was last changed
/// </summary>
DateTime ChangedDate { get; set; }
/// <summary>
/// Identity of User that deleted the record
/// </summary>
int DeletedByUserId { get; set; }
/// <summary>
/// Date when the data record was deleted
/// </summary>
DateTime DeletedDate { get; set; }
/// <summary>
/// Identity of User that created the record
/// </summary>
int CreatedByUserId { get; set; }
/// <summary>
/// Date when the data record was added
/// </summary>
DateTime CreatedDate { get; set; }
object Clone();
}
Obviously you don't have to use this, but put simply for my application implementation each type of data record is stored in its own data file (thus 1 table per file) and this is created at the beginning in the constructor.
The SQLite db connection is created using the data file path.
Table is created using the dbconnection
edit
I've had a closer look at your code.
Points to note are:
You don't appear to be creating a table.
Access to non-app folders is restricted if you chose to create a UWP rather than base WPF project - be aware of folder access permissions when running apps especially in release mode.

Related

How to determine the next primary key from a database table for a generic entity using Entity Framework Core?

I have created the following generic repository that is the parent to all of my other repositories.
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using FlasherData.Repositories.Interfaces;
namespace Data.Repositories
{
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
protected readonly DbContext _context;
public GenericRepository(DbContext context)
{
_context = context;
}
/// <summary>
/// Finds an entity of TEntity type with the given primary key value.
/// </summary>
/// <param name="id"></param>
/// <returns>The entity found or null.</returns>
public virtual TEntity Get(int id)
{
try
{
return _context.Set<TEntity>().Find(id);
}
catch (Exception e)
{
throw new Exception($"Could not find entity: {e.Message}");
}
}
/// <summary>
/// Finds an entity of TEntity type with the given primary key value.
/// </summary>
/// <param name="id"></param>
/// <returns>The entity found or null.</returns>
public virtual async Task<TEntity> GetAsync(int id)
{
try
{
return await _context.Set<TEntity>().FindAsync(id);
}
catch (Exception e)
{
throw new Exception($"Could not find entity: {e.Message}");
}
}
/// <summary>
/// Finds all entities of TEnitity type.
/// </summary>
/// <returns>A List<TEntity> of the entities found of TEntity type</returns>
public virtual IList<TEntity> GetAll()
{
try
{
return _context.Set<TEntity>().ToList();
}
catch (Exception e)
{
throw new Exception($"Could not find entities: {e.Message}");
}
}
/// <summary>
/// Asynchronously finds all entities of TEnitity type.
/// </summary>
/// <returns>A List<TEntity> of the entities found of TEntity type</returns>
public virtual async Task<IList<TEntity>> GetAllAsync()
{
try
{
return await _context.Set<TEntity>().ToListAsync();
}
catch (Exception e)
{
throw new Exception($"Could not find entities: {e.Message}");
}
}
/// <summary>
/// Filters a sequence of values of TEntity type based on a predicate.
/// </summary>
/// <param name="predicate"></param>
/// <returns>An IQueryable<TEntity> that contains elements of TEntity type from the input sequence that satisfy the condition specified by the predicate.</returns>
public virtual IEnumerable<TEntity> Where(Expression<Func<TEntity, bool>> predicate)
{
try
{
if (predicate == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} predicate must not be null");
}
return _context.Set<TEntity>().Where(predicate);
}
catch (Exception e)
{
throw new Exception($"Could not find entity: { e.Message}");
}
}
/// <summary>
/// Filters a value of TEntity type based on a predicate.
/// </summary>
/// <param name="predicate"></param>
/// <returns>An entity of TEntity type from the input sequence that satisfy the condition specified by the predicate.</returns>
public virtual TEntity WhereSingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
try
{
return _context.Set<TEntity>().SingleOrDefault(predicate);
}
catch (Exception e)
{
throw new Exception($"could not be find entity: {e.Message}");
}
}
/// <summary>
/// Asynchronously filters a value of TEntity type based on a predicate.
/// </summary>
/// <param name="predicate"></param>
/// <returns>An entity of TEntity type from the input sequence that satisfy the condition specified by the predicate.</returns>
public virtual async Task<TEntity> WhereSingleOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
try
{
return await _context.Set<TEntity>().SingleOrDefaultAsync(predicate);
}
catch (Exception e)
{
throw new Exception($"could not be find entity: {e.Message}");
}
}
/// <summary>
/// Determines if entity with the given primary key value exists.
/// </summary>
/// <param name="id"></param>
/// <returns>A boolean; true if the entity exists or false if the entity does not exist. </returns>
public virtual bool Exists(int id)
{
try
{
var response = _context.Set<TEntity>().Find(id);
if (response != null)
{
return true;
}
else
{
return false;
}
}
catch (Exception e)
{
throw new Exception($"Could not find entity: {e.Message}");
}
}
/// <summary>
/// Asynchronously determines if entity with the given primary key value exists.
/// </summary>
/// <param name="id"></param>
/// <returns>A boolean; true if the entity exists or false if the entity does not exist. </returns>
public virtual async Task<bool> ExistsAsync(int id)
{
try
{
var response = await _context.Set<TEntity>().FindAsync(id);
if (response != null)
{
return true;
}
else
{
return false;
}
}
catch (Exception e)
{
throw new Exception($"Could not find entity: {e.Message}");
}
}
/// <summary>
/// Adds an entity to the dbcontext.
/// </summary>
/// <param name="entity"></param>
/// <returns>An integer that is the primary key of the added entity.</returns>
public virtual int Add(TEntity entity)
{
try
{
if (entity == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
var result = _context.Set<TEntity>().Add(entity);
int pk = GetPrimaryKey(entity);
return pk;
}
catch (Exception e)
{
throw new Exception($"{nameof(TEntity)} could not be added: {e.Message}");
}
}
/// <summary>
/// Asynchronously adds an entity to the dbcontext.
/// </summary>
/// <param name="entity"></param>
/// <returns>An integer that is the primary key of the added entity.</returns>
public virtual async Task<int> AddAsync(TEntity entity)
{
try
{
if (entity == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
var result = await _context.Set<TEntity>().AddAsync(entity);
int pk = GetPrimaryKey(entity);
return pk;
}
catch (Exception e)
{
throw new Exception($"{nameof(TEntity)} could not be added: {e.Message}");
}
}
/// <summary>
/// Adds multiple entities to the dbcontext.
/// </summary>
/// <param name="entity"></param>
/// <returns>A List<int> that are the primary keys of the added entities.</int></returns>
public virtual IList<int> AddRange(IEnumerable<TEntity> entities)
{
try
{
List<int> pks = new List<int>();
if (entities == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
_context.Set<TEntity>().AddRange(entities);
foreach (TEntity e in entities)
{
pks.Add(GetPrimaryKey(e));
}
return pks;
}
catch (Exception e)
{
throw new Exception($"{nameof(IEnumerable<TEntity>)} could not be added: {e.Message}");
}
}
/// <summary>
/// Asynchronously adds multiple entities to the dbcontext.
/// </summary>
/// <param name="entity"></param>
/// <returns>A List<int> that are the primary keys of the added entities.</int></returns>
public virtual async Task<IList<int>> AddRangeAsync(IEnumerable<TEntity> entities)
{
try
{
List<int> pks = new List<int>();
if (entities == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
await _context.Set<TEntity>().AddRangeAsync(entities);
foreach (TEntity e in entities)
{
pks.Add(GetPrimaryKey(e));
}
return pks;
}
catch (Exception e)
{
throw new Exception($"{nameof(IEnumerable<TEntity>)} could not be added: {e.Message}");
}
}
/// <summary>
/// Updates the existing given entity.
/// </summary>
/// <param name="entity"></param>
/// <returns>An integer that is the primary key for the updated entity.</returns>
public virtual int Update(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
try
{
_context.Update(entity);
_context.SaveChanges();
return GetPrimaryKey(entity);
}
catch (Exception e)
{
throw new Exception($"{nameof(TEntity)} could not be updated: {e.Message}");
}
}
/// <summary>
/// Deletes the given entity.
/// </summary>
/// <param name="entity"></param>
public virtual void Remove(TEntity entity)
{
try
{
if (entity == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
_context.Set<TEntity>().Remove(entity);
_context.SaveChanges();
}
catch (Exception e)
{
throw new Exception($"{nameof(TEntity)} could not be removed: {e.Message}");
}
}
/// <summary>
/// Deletes multilple given entities.
/// </summary>
/// <param name="entities"></param>
public virtual void RemoveRange(IEnumerable<TEntity> entities)
{
try
{
if (entities == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
_context.Set<TEntity>().RemoveRange(entities);
_context.SaveChanges();
}
catch (Exception e)
{
throw new Exception($"{nameof(IEnumerable<TEntity>)} could not be added: {e.Message}");
}
}
/// <summary>
/// Saves changes to dbcontext for an entity
/// </summary>
/// <param name="entity"></param>
/// <returns>An integer representing the number of entites changed during the save</returns>
public virtual int SaveChanges(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
try
{
_context.Update(entity);
return _context.SaveChanges();
}
catch (Exception e)
{
throw new Exception($"{nameof(TEntity)} could not be updated: {e.Message}");
}
}
/// <summary>
/// Asynchronously saves changes to dbcontext for an entity
/// </summary>
/// <param name="entity"></param>
/// <returns>An integer representing the number of entites changed during the save</returns>
public virtual async Task<int> SaveChangesAsync(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
}
try
{
_context.Update(entity);
int entitiesChanged = await _context.SaveChangesAsync();
return entitiesChanged;
}
catch (Exception e)
{
throw new Exception($"{nameof(TEntity)} could not be updated: {e.Message}");
}
}
/// <summary>
/// Finds the primary key of the given entity
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"></param>
/// <returns>An integer that is the primary key for the given entity.</returns>
public virtual int GetPrimaryKey(TEntity entity)
{
var keyName = _context.Model.FindEntityType(typeof(TEntity)).FindPrimaryKey().Properties
.Select(x => x.Name).Single();
return (int)entity.GetType().GetProperty(keyName).GetValue(entity, null);
}
}
}
I need to add a generic function where I can extract the next primary key from the database using entity framework.
We have been asked to not use GUIDs to make queries easier for analysts and to use an ORM to stay database neutral (all queries, etc... done via ORM).
We may have to tell them that they must choose between these two requirements, but we hope to find a solution that meets these requirements and also does not have conflicts with concurrency.
This is what I have so far, but I have not been able to get the primary key value form the Key object.
public virtual int NextPrimaryKey()
{
int nextPrimaryKey = 0;
var maxKey = _context.Model.FindEntityType(typeof(TEntity)).GetKeys().Max();
//nextPrimarykey = ;
return nextPrimaryKey;
}
Part of my problems is likely that I am new to generics so I do not know exactly what to look for or how to ask it.
Is there a better approach?
If this is a good approach, how to I extract the primary key value from the Key object?
Getting the primary key, generally, is not a good idea because it is an unpredictable action. At the time of returning the 'next' incremental value, it might already be in use because in the meantime your database was updated. If you'd like to know a key beforehand, you should probably use a GUID (either add it as an extra column, or use it as the primary key).

Cosmos DB - CreateCollectionIfNotExistsAsync Generic method

I am using cosmos DB and I have created below generic repository for CRUD operations.
public class CosmosDBRepository : ICosmosDBRepository
{
private readonly DocumentClient _client;
private readonly string DatabaseId = "FleetHub";
public CosmosDBRepository()
{
var endpoint = CloudConfigurationManager.GetSetting("CosmoDbEndpoint");
var authkey = CloudConfigurationManager.GetSetting("CosmoDbAuthKey");
try
{
if (endpoint == null || authkey == null)
{
throw new ArgumentNullException("CosmoDbEndpoint or CosmoDbAuthKey could not be found in the config file, check your settings.");
}
if (_client == null)
{
_client = new DocumentClient(new Uri(endpoint), authkey, connectionPolicy: new ConnectionPolicy { EnableEndpointDiscovery = false });
}
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}
catch (Exception e)
{
throw new Exception($"Initialise failed CosmoDbEndpoint {endpoint} or CosmoDbAuthKey {authkey} could not be found in the config file, check your settings. {e.Message}");
}
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="partitionkey"></param>
/// <returns></returns>
public async Task<T> GetItemAsync<T>(string id, string partitionkey) where T : class
{
try
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
Document document = await _client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionkey) });
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public async Task<Document> CreateItemAsync<T>(T item) where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
return await _client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
}
public async Task<IEnumerable<T>> GetItemsAsync<T>(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByDesc, int takeCount = -1)
where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
var criteria = _client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), new FeedOptions { EnableCrossPartitionQuery = true })
.Where(predicate)
.OrderByDescending(orderByDesc)
.AsDocumentQuery();
IDocumentQuery<T> query = criteria;
List<T> results = new List<T>();
while (query.HasMoreResults)
{
if (takeCount > -1 && results.Count >= takeCount)
{
break;
}
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="item"></param>
/// <returns></returns>
public async Task<Document> UpdateItemAsync<T>(string id, T item) where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
return await _client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
}
#region private methods
private async Task CreateDatabaseIfNotExistsAsync()
{
try
{
await _client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await _client.CreateDatabaseAsync(new Database { Id = DatabaseId });
}
else
{
throw;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private string GetPartitionKeyAttributeCosmoDbCollection(Type t)
{
// Get instance of the attribute.
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
if (attribute == null)
{
throw new Exception("The attribute CosmoDbCollection was not found.");
}
return attribute.PartitionKey;
}
private string GetAttributeCosmoDbCollection<T>(Type t) where T : class
{
// Get instance of the attribute.
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
if (attribute == null)
{
throw new Exception("The attribute CosmoDbCollection was not found.");
}
return attribute.Name;
}
#endregion
}
Here is CosmoDBCollection class:
public class CosmoDBCollection : Attribute
{
public string Name { get; set; }
public string PartitionKey { get; set; }
}
I am calling CreateCollectionIfNotExistsAsync().Wait(); in the constructor and this method required collectionId. How Can I pass CollectionId to this method? As this is the generic repository.
Do I need to create a Generic CreateCollectionIfNotExistsAsync() method?
If your collection name is based off <T>, why not simply have CosmosDBRepository<T> as the actual class. That way you can get the value also on the constructor.
Ideally it would also be a readonly private property that you only calculate once (on the constructor) and reuse on all operations to avoid paying the cost to construct it later on (since it doesn't change).

NHibernate KeyNotFoundException

My ASP.NET application runs fine in local instance of VS 2012 but not in VS 2015. It is throwing
Systems.Collections.Generic.KeyNotFoundException occurred in mscorlib.dll but not handled in user code
The application also runs fine when deployed on the server but issue occurs only in local machine - NHibernate session key being null and breaks on the following line.
var sessionInitializer = map[sessionFactory]
My code is pasted below and I am following similar implementation as in the following link (I have everything up until the IWindsorInstaller section from the link) -
http://nhibernate.info/blog/2011/03/02/effective-nhibernate-session-management-for-web-apps.html
public class LazyNHWebSessionContext : ICurrentSessionContext
{
private readonly ISessionFactoryImplementor factory;
private const string CurrentSessionContextKey =
"NHibernateCurrentSession";
public LazyNHWebSessionContext(ISessionFactoryImplementor factory)
{
this.factory = factory;
}
/// <summary>
/// Retrieve the current session for the session factory.
/// </summary>
/// <returns></returns>
public ISession CurrentSession()
{
Lazy<ISession> initializer;
var currentSessionFactoryMap = GetCurrentFactoryMap();
if (currentSessionFactoryMap == null ||
!currentSessionFactoryMap.TryGetValue(factory, out initializer))
{
return null;
}
return initializer.Value;
}
/// <summary>
/// Bind a new sessionInitializer to the context of the sessionFactory.
/// </summary>
/// <param name="sessionInitializer"></param>
/// <param name="sessionFactory"></param>
public static void Bind(Lazy<ISession> sessionInitializer, ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
map[sessionFactory] = sessionInitializer;
}
/// <summary>
/// Unbind the current session of the session factory.
/// </summary>
/// <param name="sessionFactory"></param>
/// <returns></returns>
public static ISession UnBind(ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
var sessionInitializer = map[sessionFactory];
map[sessionFactory] = null;
if (sessionInitializer == null || !sessionInitializer.IsValueCreated) return null;
return sessionInitializer.Value;
}
/// <summary>
/// Provides the CurrentMap of SessionFactories.
/// If there is no map create/store and return a new one.
/// </summary>
/// <returns></returns>
private static IDictionary<ISessionFactory, Lazy<ISession>> GetCurrentFactoryMap()
{
//var contextItem = HttpContext.Current.Items[CurrentSessionContextKey];
if (HttpContext.Current == null) return null;
var currentFactoryMap = (IDictionary<ISessionFactory, Lazy<ISession>>)
HttpContext.Current.Items[CurrentSessionContextKey];
if (currentFactoryMap == null)
{
currentFactoryMap = new Dictionary<ISessionFactory, Lazy<ISession>>();
HttpContext.Current.Items[CurrentSessionContextKey] = currentFactoryMap;
}
return currentFactoryMap;
}
}

Generic Object Cache

I am working on a project where I plan on using Redis as persistent data storage, however the task at hand, I am working on a generic Object cache. and as a huge fan of LINQ I have started designing a cache which does support this.
public ConcurrentBag<Object> Cache = new ConcurrentBag<object>();
public List<T> FindBy<T>(Func<T, bool> predicate) where T : class
{
var tmp = new List<T>();
foreach (var i in Cache)
{
try
{
T obj = i as T;
if (obj != null)
tmp.Add(obj);
}
catch { }
}
return tmp.Where(predicate).ToList();
}
I am afraid that when the object cache grows large it will become inefficient. (I estimate 500k-1m objects)
I was hoping that it would be possible to use something like this
public ConcurrentBag<Object> Cache = new ConcurrentBag<object>();
public List<T> FindBy<T>(Func<T, bool> predicate) where T : class
{
return Cache.Where<T>(predicate).ToList();
}
Hopefully I am not all off-track here? Any suggestions are welcome :)
Hash your genric type and save list of specific type..
Something like:
Dictionary<Type,List<T>>
Then get value by type key and query as you wanted
Since you estimate a lot of items in the cache and the operations on the cache will be type specific, you could use multiple bags wrapped into a dictionary. That would speed up finding the subset of the cache of type of interest and would be ideal if the cache contained many minimal subsets of different types.
readonly IDictionary<Type, ConcurrentBag<object>> _cache = new ConcurrentDictionary<Type, ConcurrentBag<object>>();
public List<T> FindBy<T>(Func<T, bool> predicate) where T : class
{
// Check if items of type {T} exist in the cache.
ConcurrentBag<object> bag;
if (_cache.TryGetValue(typeof (T), out bag))
{
// Cast, apply predicate and return.
return bag.Cast<T>().Where(predicate).ToList();
}
// Return an empty list.
return new List<T>();
}
Of course now you also need to handle adding items properly to the cache to ensure that different types will be put into their corresponding bags.
Big thanks to both Discosultan and user1190916 Whom both pointed me in the right direction in what I needed to get a CRUD cached-object repository with full LINQ support using Redis for persistent storage (Client ServiceStack.Redis), this is what I have managed to conjure up thus far.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Collections.Concurrent;
using ServiceStack.Redis;
namespace RedisTestRepo
{
class Program
{
//public static DataRepository Db;
static void Main(string[] args)
{
Repo r = new Repo();
// We do not touch sequence, by running example we can see that sequence will give Users new unique Id.
// Empty data store.
Console.WriteLine("Our User Data store should be empty.");
Console.WriteLine("Users In \"Database\" : {0}\n", r.All<User>().Count);
// Add imaginary users.
Console.WriteLine("Adding 100 imaginairy users.");
for (int i = 0; i < 99; i++)
r.Create<User>(new User { Id = r.Next<User>(), Name = "Joachim Nordvik" });
// We should have 100 users in data store.
Console.WriteLine("Users In \"Database\" : {0}\n", r.All<User>().Count);
// Lets print 10 users from data store.
Console.WriteLine("Order by Id, Take (10) and print users.");
foreach (var u in r.All<User>().OrderBy(z => z.Id).Take(10))
{
Console.WriteLine("ID:{0}, Name: {1}", u.Id, u.Name);
// Lets update an entity.
u.Name = "My new Name";
r.Update<User>(x=>x.Id == u.Id, u);
}
// Lets print 20 users from data store, we already edited 10 users.
Console.WriteLine("\nOrder by Id, Take (20) and print users, we previously edited the users that we printed lets see if it worked.");
foreach (var u in r.All<User>().OrderBy(z => z.Id).Take(20))
{
Console.WriteLine("ID:{0}, Name: {1}", u.Id, u.Name);
}
// Clean up data store.
Console.WriteLine("\nCleaning up Data Store.\n");
foreach (var u in r.All<User>())
r.Delete<User>(u);
// Confirm that we no longer have any users.
Console.WriteLine("Confirm that we no longer have User entities in Data Store.");
Console.WriteLine("Users In \"Database\" : {0}\n\n", r.All<User>().Count);
Console.WriteLine("Hit return to exit!");
Console.Read();
}
}
public class Repo
{
private static readonly PooledRedisClientManager m = new PooledRedisClientManager();
public Repo()
{
// Spool Redis Database into our object cache.
LoadIntoCache<User>();
}
readonly IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();
/// <summary>
/// Load {T} into object cache from Data Store.
/// </summary>
/// <typeparam name="T">class</typeparam>
private void LoadIntoCache<T>() where T : class
{
_cache[typeof(T)] = GetAll<T>().Cast<object>().ToList();
}
/// <summary>
/// Add single {T} into cache and Data Store.
/// </summary>
/// <typeparam name="T">class</typeparam>
/// <param name="entity">class object</param>
public void Create<T>(T entity) where T : class
{
List<object> list;
if (!_cache.TryGetValue(typeof(T), out list))
{
list = new List<object>();
}
list.Add(entity);
_cache[typeof(T)] = list;
Store<T>(entity);
}
/// <summary>
/// Delete single {T} from cache and Data Store.
/// </summary>
/// <typeparam name="T">class</typeparam>
/// <param name="entity">class object</param>
public void Delete<T>(T entity) where T : class
{
List<object> list;
if (_cache.TryGetValue(typeof(T), out list))
{
list.Remove(entity);
_cache[typeof(T)] = list;
RedisDelete<T>(entity);
}
}
/// <summary>
/// Tries to update or Add entity to object cache and Data Store.
/// </summary>
/// <typeparam name="T">class</typeparam>
/// <param name="predicate">linq expression</param>
/// <param name="entity">entity</param>
public void Update<T>(Func<T, bool> predicate, T entity) where T : class
{
List<object> list;
if (_cache.TryGetValue(typeof(T), out list))
{
// Look for old entity.
var e = list.Cast<T>().Where(predicate).FirstOrDefault();
if(e != null)
{
list.Remove(e);
}
// Regardless if object existed or not we add it to our Cache / Data Store.
list.Add(entity);
_cache[typeof(T)] = list;
Store<T>(entity);
}
}
/// <summary>
/// Find List<T>(predicate) in cache.
/// </summary>
/// <typeparam name="T">class</typeparam>
/// <param name="predicate">linq statement</param>
/// <returns></returns>
public List<T> FindBy<T>(Func<T, bool> predicate) where T : class
{
List<object> list;
if (_cache.TryGetValue(typeof(T), out list))
{
return list.Cast<T>().Where(predicate).ToList();
}
return new List<T>();
}
/// <summary>
/// Find All {T}
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>List<T></returns>
public List<T> All<T>() where T : class
{
return GetAll<T>().ToList();
}
/// <summary>
/// Find Single {T} in object cache.
/// </summary>
/// <typeparam name="T">class</typeparam>
/// <param name="predicate">linq statement</param>
/// <returns></returns>
public T Read<T>(Func<T, bool> predicate) where T : class
{
List<object> list;
if (_cache.TryGetValue(typeof(T), out list))
{
return list.Cast<T>().Where(predicate).FirstOrDefault();
}
return null;
}
public long Next<T>() where T : class
{
long id = 1;
using (var ctx = m.GetClient())
{
try
{
id = ctx.As<T>().GetNextSequence();
}
catch(Exception ex)
{
// Add exception handler.
}
}
return id;
}
private void RedisDelete<T>(T entity) where T : class
{
using (var ctx = m.GetClient())
ctx.As<T>().Delete(entity);
}
private T Find<T>(long id) where T : class
{
using (var ctx = m.GetClient())
return ctx.As<T>().GetById(id);
}
private IList<T> GetAll<T>() where T : class
{
using(var ctx = m.GetClient())
{
try
{
return ctx.As<T>().GetAll();
}
catch
{
return new List<T>();
}
}
}
private void Store<T>(T entity) where T : class
{
using (var ctx = m.GetClient())
ctx.Store<T>(entity);
}
}
public class User
{
public long Id { get; set; }
public string Name { get; set; }
}
}

Comparing a List<T> with another List<t>

I have been reading on how to compare a list with one annother. I have tried to implement the IEquatable interface. Here is what i have done so far:
/// <summary>
/// A object holder that contains a service and its current failcount
/// </summary>
public class ServiceHolder : IEquatable<ServiceHolder>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="service"></param>
public ServiceHolder(Service service)
{
Service = service;
CurrentFailCount = 0;
}
public Service Service { get; set; }
public UInt16 CurrentFailCount { get; set; }
/// <summary>
/// Public equal method
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
ServiceHolder tmp = obj as ServiceHolder;
if (tmp == null)
{
return false;
}
else
{
return Equals(tmp);
}
}
/// <summary>
/// Checks the internal components compared to one annother
/// </summary>
/// <param name="serviceHolder"></param>
/// <returns>tru eif they are the same else false</returns>
public bool Equals(ServiceHolder serviceHolder)
{
if (serviceHolder == null)
{
return false;
}
if (this.Service.Id == serviceHolder.Service.Id)
{
if (this.Service.IpAddress == serviceHolder.Service.IpAddress)
{
if (this.Service.Port == serviceHolder.Service.Port)
{
if (this.Service.PollInterval == serviceHolder.Service.PollInterval)
{
if (this.Service.ServiceType == serviceHolder.Service.ServiceType)
{
if (this.Service.Location == serviceHolder.Service.Location)
{
if (this.Service.Name == this.Service.Name)
{
return true;
}
}
}
}
}
}
}
return false;
}
}
and this is where I use it:
private void CheckIfServicesHaveChangedEvent()
{
IList<ServiceHolder> tmp;
using (var db = new EFServiceRepository())
{
tmp = GetServiceHolders(db.GetAll());
}
if (tmp.Equals(Services))
{
StateChanged = true;
}
else
{
StateChanged = false;
}
}
Now when I debug and I put a break point in the equals function it never gets hit.
This leads me to think I have implemented it incorrectly or Im not calling it correctly?
If you want to compare the contents of two lists then the best method is SequenceEqual.
if (tmp.SequenceEquals(Services))
This will compare the contents of both lists using equality semantics on the values in the list. In this case the element type is ServiceHolder and as you've already defined equality semantics for this type it should work just fine
EDIT
OP commented that order of the collections shouldn't matter. For that scenario you can do the following
if (!tmp.Except(Services).Any())
You can compare lists without the order most easily with linq.
List<ServiceHolder> result = tmp.Except(Services).ToList();

Categories