Azure Table Generics - Operation not supported on ExecuteQuery - c#

I'm trying to create a generic implementation for Azure Tables. The ploblem is that when I use the ExecuteQuery function it always return the following error to me:
Error = Unable to evaluate the expression. Operation not supported.
Unknown error: 0x80070057.
I do can run the Execute function for TableOperation Delete, Update, Create, Retrieve for example
That's the classes I created on my project:
Base class
public abstract class TableEntityBase : TableEntity
{
private string TableName { get; set; }
public TableEntityBase(string tableName)
{
TableName = tableName;
}
public string GetTableName() => TableName;
}
Then its Interface
public interface ITableEntityBase<T> where T : TableEntityBase
{
TableResult InsertOrMerge(T entity);
TableResult Delete(T id);
IEnumerable<T> GetByExpression(string query);
IEnumerable<T> GetAll();
}
And the classes for the tables I have
public class Mapping : TableEntityBase
{
public Mapping() :
base(EntityLogicalName)
{
}
private const string EntityLogicalName = "Mapping";
public string Source { get; set; }
}
public interface IMapping : ITableEntityBase<Mapping>
{
}
At least, my service class
public class TableEntityBaseServices<T> : ITableEntityBase<T> where T : TableEntityBase, new()
{
protected CloudTable _cloudTable;
protected string tableName = ((T)Activator.CreateInstance(typeof(T))).GetTableName();
public TableEntityBaseServices()
{
IConfiguration appSettings = AppSettings.GetAppSettings().GetSection("ConnectionStrings");
_cloudTable = CloudStorageAccountExtensions.CreateCloudTableClient(CloudStorageAccount.Parse(appSettings.GetSection("AzureConfig").Value)).GetTableReference(tableName);
_cloudTable.CreateIfNotExistsAsync();
}
//...Other methods that work well
IEnumerable<T> ITableEntityBase<T>.GetByExpression(string query)
{
return _cloudTable.ExecuteQuery<T>(new TableQuery<T>().Where(query)); //Error here: Unable to evaluate the expression. Operation not supported.
}
}
The Mapping service then is:
public class MappingServices : TableEntityBaseServices<Mapping>, IMapping { }
The method call should be simple
static async Task Main(string[] args)
{
var serviceProvider = new ServiceCollection()
.AddSingleton<IMapping, MappingServices>()
.BuildServiceProvider();
IMapping _mappingService = serviceProvider.GetRequiredService<IMapping>();
try
{
IEnumerable<Mapping> mappings = _mappingService.GetByExpression(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "test1"));
}
catch (Exception e)
{
throw e;
}
}
I saw this answer to a question but in my case I don't know what I need to do, since I already define the new() on my service class. Where did I messed up?
Thanks in advance :)

Please use the package Microsoft.Azure.Cosmos.Table 1.0.8 if you're not.
I'm testing with your code, no error occurs. The test result as below:

Related

Is it possible to create a C# record with a private constructor?

Hello,
I´m trying to rebuild a discriminated union type in C#.
I always created them with classes like this:
public abstract class Result
{
private Result() { }
public sealed class Ok : Result
{
public Ok(object result) // don´t worry about object - it´s a sample
=> Result = result;
public object Result { get; }
}
public sealed class Error : Result
{
public Error(string message)
=> Message = message;
public string Message { get; }
}
}
The problem is that is sooooo much boilerplate code when comparing to F#:
type Result =
| Ok of result : object
| Error of message : string
So I tried to rebuild the type with the help of C#9 records.
public abstract record Result
{
public sealed record Ok(object result) : Result;
public sealed record Error(string message) : Result;
}
Now it is way less code but now there is the problem that anyone can make new implementations of Result because the record has a public constructor.
Dose anyone have an idea how to restrict the implementations of the root record type?
Thanks for your help and your ideas! 😀 💡
I solved it with the help of your comments and this other stackoverflow article.
namespace System.Runtime.CompilerServices
{
internal static class IsExternalInit { }
}
namespace RZL.Core.Abstractions.DMS
{
public abstract record Result
{
private Result() { }
public sealed record Ok(object result) : Result;
public sealed record Error(string message) : Result;
}
}
If you don't want to abstract the record you don't have to:
public record ClientVerificationResponse
{
protected ClientVerificationResponse(bool succeeded)
{
Succeeded = succeeded;
}
[MemberNotNullWhen(true, nameof(Credentials))]
public bool Succeeded { get; init; }
public ClaimsPrincipal? Credentials { get; init; }
public static ClientVerificationResponse Success(ClaimsPrincipal claimsPrincipal) => new(true) { Credentials= claimsPrincipal };
public static ClientVerificationResponse Fail => new(false);
}

MongoDb C# Driver Projection after GroupBy with generic type

I've spotted an issue while working with mongodb c# driver (v 2.11.1)
I need to perform GroupBy and after select first id from each group.
When working on concrete IMongoQueryable it is working fine.
However when I wrapped it with some Generic helper class I got exception with unsupported method message.
here is code of dotnet core console application which shows the error. It looks like Select after groupby is not implemented for generic only for concrete.
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var sut = new Test<Quote>();
var workingTest1 = sut.QueryableCollection.GroupBy(x => x._id).Select(x => x.First()._id).ToString();
var workingTest2 = sut.TestCallWithCasting();
var notWorkingTest = sut.TestCallWithoutCasting();
}
}
public class Test<TEntity> where TEntity : IMongoDbEntity
{
private IMongoCollection<TEntity> _collection;
public IMongoQueryable<TEntity> QueryableCollection => _collection.AsQueryable();
public Test()
{
var client = new MongoClient();
var database = client.GetDatabase("Quote");
_collection = database.GetCollection<TEntity>("quotes");
}
public string TestCallWithCasting()
{
var t1 = ((IMongoQueryable<Quote>)QueryableCollection).GroupBy(x => x._id).Select(x => x.First()._id).ToString();
return t1;
}
public string TestCallWithoutCasting()
{
try
{
return QueryableCollection.GroupBy(x => x._id).Select(x => x.First()._id).ToString();
}
catch (Exception ex)
{
return ex.Message;
}
}
}
public class Quote : IMongoDbEntity
{
public string _id { get; set; }
}
public interface IMongoDbEntity : IEntity
{
string _id { get; set; }
}
public interface IEntity
{
}
}
Looks like IMongoQueryable<T> behaves differently if T is only known to be an interface. TestCallWithoutCasting doesn't throw exception if you add class before IMongoDbEntity in TEntity : IMongoDbEntity.
So finally it's like:
public class Test<TEntity> where TEntity : class, IMongoDbEntity

How to correctly abstract data access layer (for database, rest api calls, json) in C#?

I've been developing an application that uses various data connections (like database, rest api calls, json config files) in C#. I'm currently struggling to create a sensible data access layer abstraction that would enable to switch between these easily. Each of these require a different connection settings and also work differently.
I've looked at the example of the Repository pattern, but this doesn't really suit my needs. I want to be able to define some query pattern, which I can parametrize and that query will be able to handle the parameters. Example of what I currently have:
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
public class DatabaseQuery<TResult> : IQuery<IEnumerable<TResult>>
{
public string ConnectionString { get; set; }
public string CommandText { get; set; }
}
public class DatabaseConnection<TQuery, TResult> : IQueryHandler<TQuery, IEnumerable<TResult>>
where TQuery : DatabaseQuery<TResult>
{
public IEnumerable<TResult> Handle(TQuery query)
{
var results = new List<TResult>();
using (var connection = new SqlConnection(query.ConnectionString))
using (var command = new SqlCommand(query.CommandText, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
results.Add(...
}
}
}
return results;
}
}
public class JsonQuery<TResult> : IQuery<IEnumerable<TResult>>
{
public string FileLocation { get; set; }
public Func<TResult, bool> Condition { get; set; }
}
public class JsonConnection<TQuery, TResult> : IQueryHandler<TQuery, IEnumerable<TResult>>
where TQuery : JsonQuery<TResult>
{
public IEnumerable<TResult> Handle(TQuery query)
{
var text = File.ReadAllText(query.FileLocation);
return Deserialize<TResult>(text).Results.Where(query.Condition);
}
}
public interface IQueryBuilder<TQuery, TParameters>
{
TQuery Build(TParameters parameters);
}
public class GetAccountsByStatusAndBalanceHigherThanQueryParameters
{
public string Status { get; set; }
public decimal Balance { get; set; }
}
public class GetAccountsByStatusAndBalanceHigherThan_DatabaseQueryBuilder :
IQueryBuilder<DatabaseQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
{
public DatabaseQuery<Account> Build(GetAccountsByStatusAndBalanceHigherThanQueryParameters parameters)
{
return new DatabaseQuery<Account>()
{
ConnectionString = "connString",
CommandText = $"SELECT * FROM Accounts WHERE Status = {parameters.Status} AND Balance = {parameters.Balance}"
};
}
}
public class GetAccountsByStatusAndBalanceHigherThan_JsonQueryBuilder
: IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
{
public JsonQuery<Account> Build(GetAccountsByStatusAndBalanceHigherThanQueryParameters parameters)
{
return new JsonQuery<Account>()
{
FileLocation = "fileLocation",
Condition = acc => acc.Status == parameters.Status && acc.Balance > parameters.Balance
};
}
}
public class GetAccountsByStatusAndBalanceHigherThanQuery : IQuery<IEnumerable<Account>>
{
public string Status { get; set; }
public decimal Balance { get; set; }
}
public class GetAccountsByStatusAndBalanceHigherThanQueryHandler :
IQueryHandler<GetAccountsByStatusAndBalanceHigherThanQuery, IEnumerable<Account>>
{
private readonly IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
_queryBuilder;
private readonly IQueryHandler<JsonQuery<Account>, IEnumerable<Account>> _connection;
public GetAccountsByStatusAndBalanceHigherThanQueryHandler(
IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters> queryBuilder,
IQueryHandler<JsonQuery<Account>, IEnumerable<Account>> connection)
{
_queryBuilder = queryBuilder;
_connection = connection;
}
public IEnumerable<Account> Handle(GetAccountsByStatusAndBalanceHigherThanQuery query)
{
var jsonQuery = _queryBuilder.Build(new GetAccountsByStatusAndBalanceHigherThanQueryParameters
{
Status = query.Status,
Balance = query.Balance
});
return _connection.Handle(jsonQuery);
}
}
So there are two connections - one database and one Json file connection. I have put the settings to the connections into queries - and while database connection requires connection string and SQL command, the Json connection requires file location and some filtering on the results. The problem is in the last query handler - GetAccountsByStatusAndBalanceHigherThanQueryHandler. I need to make that depend on specific connection, otherwise I can't get it to compile. What I want is to make sure that I can change the connection by just changing the injected parameters and all will work correctly.
Could you please advise on how to make sure that I can change the connections easily and also whether this architecture is good at all?
I think you may be overcomplicating this. It looks to me like you have two data sources to retrieve the same data - one is a json data source and a database. This fits pretty neatly into the land of "one interface, multiple implementations". You'll also need a class to sort out which implementation you should use (this is a perfect use case for a factory). The complicated querying logic you're trying to pass into the constructors you could pass as method arguments.
Code would look something like this:
public interface IAccountDataAccess
{
IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance);
// etc.
}
public class JsonAccountDataAccess : IAccountDataAccess
{
private string jsonFilePath;
public JsonAccountDataAccess(string _jsonFilePath)
{
jsonFilePath = _jsonFilePath;
}
public IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance)
{
// read json file, extract data, etc.
}
}
public class DatabaseAccountDataAccess : IAccountDataAccess
{
private string connectionString;
public DatabaseAccountDataAccess(string _connectionString)
{
connectionString = _connectionString;
}
public IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance)
{
// read database, extract data, etc.
}
}
Here's the tricky part - you need a factory to spit out the correct implementation given some input. I'm not sure how you're planning to decide whether to use JSON or the database, but assuming that your client class knows:
public class AccountDataAccessFactory
{
public IAccountDataAccess GetDataAccess(bool useDatabase)
{
if(useDatabase) // you could use arbitrarily complex logic here
return new DatabaseAccountDataAccess(connString);
else
return new JsonAccountDataAccess(jsonFilePath);
}
}
Your client class could use it like this:
var factory = new AccountDataAccessFactory();
var dataAccess = factory.GetDataAccess(true);
var accounts = dataAccess.GetAccountsHigherThanBalance(status, balance);

Fluent Nhibernate : How to make Search Class Generic in best possible way

I have a class say 'AllInvoices', the structure of which is as below :
public class ActiveInvoices
{
public string InvoiceId { get; set; }
public string InvoiceIssueDate { get; set; }
public string InvoiceTransactionDate { get; set; }
public string InvoiceExpiryDate { get; set; }
}
The mapping class for Entity ActiveInvoices is
public class ActiveInvoicesMap : ClassMap<ActiveInvoices>
{
public ActiveInvoicesMap()
{
Id(x => x.InvoiceId);
Map(x => x.InvoiceIssueDate);
Map(x => x.InvoiceTransactionDate);
Map(x => x.InvoiceExpiryDate);
}
}
Now with this entity I search for Active Invoices in database with the following class
public class SearchInvoices
{
public readonly IRepository<ActiveInvoices> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<ActiveInvoices> activeInvoicesRepository)
{
latestActiveInvoicesRepository = activeInvoicesRepository;
}
public List<ActiveInvoices> GetActiveInvoices()
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
To Search Active Invoices I call the Search Class method 'GetActiveInvoices()' from a workflow class which looks like below :
public class CurrentWorkFlow
{
public void GetActiveInvoices()
{
var invoiceSearch = new SearchInvoices(IRepository <ActiveInvoices> repository);
}
}
Now the issue in hand is that I need to make class 'SearchInvoices' generic to support all other possible types that i would create like 'ExpiredInvoices', 'ArchivedInvoices', 'FutureInvoices' etc and not just only for type 'ActiveInvoices'.
These new types may or may not have the same structure as 'ActiveInvoices'.
I have tried to use dynamic but thought of asking experts around here if they have any better ideas to implement the required functionality
in most optimized generic manner.
Regrets for being very detailed and lengthy in asking but i thought to include as many details as i can. Hope it goes well with you folks.
Couldn't you make a generic repository like this? -
interface IDomain{
}
class ExpiredInvoices: IDomain{
}
class ActiveInvoices: IDomain{
}
interface IRepository{
}
class Repsoitory: IRepository {
public static IList<T> Get<T>() where T: IDomain //default one
{
using (ISession session = OpenEngineSession())
{
return session.Query<T>().ToList();
}
}
public static IList<T> Get<T>(Expression<Func<T, bool>> expression) where T: IDomain // overloaded get with linq predicate
{
using (ISession session = OpenEngineSession())
{
return session.Query<T>().Where(expression).ToList();
}
}
}
Then use it like -
var repo = // get IRepository
var activeInvoices = repo.Get<ActiveInvoices>();
var expiredInvoices = repo.Get<ExpiredInvoices>();
EDIT: As Repository cannot be changed, suggested by OP
If you cannot change the repository, then I would suggest making the search service interface dependent, rather than concrete class -
interface IInvoice{
}
class ExpiredInvoices: IInvoice{
}
class ActiveInvoices: IInvoice{
}
public class SearchInvoices
{
public readonly IRepository<IInvoice> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<IInvoice> activeInvoicesRepository)
{
latestInvoicesRepository = activeInvoicesRepository;
}
public List<T> GetActiveInvoices<T>() where T: IInvoice
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
Then call like -
var ss = new SearchService(IRepository <ActiveInvoices> repository);
var items = ss.GetActiveInvoices<ActiveInvoices>();
Or,
public class SearchInvoices<T> where T: IInvoice
{
public readonly IRepository<T> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<T> activeInvoicesRepository)
{
latestInvoicesRepository = activeInvoicesRepository;
}
public List<T> GetActiveInvoices()
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
then call like -
var ss = new SearchService<ActiveInvoices>(IRepository <ActiveInvoices> repository);
var items = ss.GetActiveInvoices();
Whichever suits you.

Optimize the use of Generic Repository using linq to sql c#

I've Generic Repository Class like this:
public class Repository : IDisposable
{
public static DataContext context { get; set; }
public static void Insert<T>(T item) where T : class
{
try
{
var table = context.GetTable<T>();
table.InsertOnSubmit(item);
context.SubmitChanges();
}
catch (Exception)
{
throw;
}
}
public void Dispose()
{
context.Dispose();
}
}
Above one is my Generic Class for Inserting Entity using Linq to sql.
I've total 10 entities in my datacontext and i'm writing 10 Insert methods like this(Example i'm providing 3 methods).
public void AddStudent(Student st)
{
Repository.Insert<Student>(st);
}
public void AddEmployee(Employee emp)
{
Repository.Insert<Employee>(emp);
}
public void AddStudent(Product prod)
{
Repository.Insert<Product>(prod);
}
like this I've 10 methods. is there a way to optimize this code. like this
I want to create a class with Add method and i'll use this add method entire my app where ever it is required.
public class Class1
{
public void Add(Table table)
{
Repository.Insert<Table>(table);
}
}
I want to use like this Class1 cls1 = new Class1(); cls1.Add(StudentObject);
can please suggest the way to implement class.
You could define a generic class rather than just a method:
public class Repository<T> : IDisposable
{
public static DataContext context { get; set; }
public static void Insert(T item)
{
var table = context.GetTable<T>();
table.InsertOnSubmit(item);
context.SubmitChanges();
}
public void Dispose()
{
context.Dispose();
}
}
And you then get the following, rather than all the additional methods:
var repo = new Repository<Product>();
repo.Insert(aProduct);

Categories

Resources