I have been trying create my own DbProvider and configure it with EnterpriseLibrary but I'm running through below issue
Parameter discovery is not supported for connections using GenericDatabase. You must specify the parameters explicitly, or configure the connection to use a type deriving from Database that supports parameter discovery.
I have Created Connection class which implements DbConnection and other classes like classes which implmenets DbCommand etc
I have overriden the DbConnection class and the methods which I dont know implementation I have thrown Not implemented exception like
public override string Database
{
get
{
throw new NotImpelmentedException();
}
}
And I have created enterpriselibrary connection as below
public Database GetConnection()
{
CustomDbProviderFactory obj = new CustomDbProviderFactory();
GenericDatabase db = new GenericDatabase("server=****;Request Timeout=3000000;", obj);
return db;
}
but when I execute DataReader with conection string and command I 'm getting issue I have mentioned
I have resolved this issue,
While using generic database object , I was using like this
db.ExecuteReader("Select * from employees");
instead it should be
db.ExecuteReader(CommandType.Text,"Select * from employees");
Related
I know that this question was asked already, but it seems that some more things have to be clarified. :)
Database is designed in the way that each user has proper privileges to read documents, so the connection pool needs to have a connection with different users, which is out of connection pool concept. Because of the optimization and the performance I need to call so-called "user preparation" which includes setting session variables, calculating and caching values in a cache, etc, and after then execute queries.
For now, I have two solutions. In the first solution, I first check that everything is prepared for the user and then execute one or more queries. In case it is not prepared then I need to call "user preparation", and then execute query or queries. With this solution, I lose a lot of performance because every time I have to do the checking and so I've decided for another solution.
The second solution includes "database pool" where each pool is for one user. Only at the first connection useCount === 0 (I do not use {direct: true}) I call "user preparation" (it is stored procedure that sets some session variables and prepares cache) and then execute sql queries.
User preparation I’ve done in the connect event within the initOptions parameter for initializing the pgPromise. I used the pg-promise-demo so I do not need to explain the rest of the code.
The code for pgp initialization with the wrapper of database pooling looks like this:
import * as promise from "bluebird";
import pgPromise from "pg-promise";
import { IDatabase, IMain, IOptions } from "pg-promise";
import { IExtensions, ProductsRepository, UsersRepository, Session, getUserFromJWT } from "../db/repos";
import { dbConfig } from "../server/config";
// pg-promise initialization options:
export const initOptions: IOptions<IExtensions> = {
promiseLib: promise,
async connect(client: any, dc: any, useCount: number) {
if (useCount === 0) {
try {
await client.query(pgp.as.format("select prepareUser($1)", [getUserFromJWT(session.JWT)]));
} catch(error) {
console.error(error);
}
}
},
extend(obj: IExtensions, dc: any) {
obj.users = new UsersRepository(obj);
obj.products = new ProductsRepository(obj);
}
};
type DB = IDatabase<IExtensions>&IExtensions;
const pgp: IMain = pgPromise(initOptions);
class DBPool {
private pool = new Map();
public get = (ct: any): DB => {
const checkConfig = {...dbConfig, ...ct};
const {host, port, database, user} = checkConfig;
const dbKey = JSON.stringify({host, port, database, user})
let db: DB = this.pool.get(dbKey) as DB;
if (!db) {
// const pgp: IMain = pgPromise(initOptions);
db = pgp(checkConfig) as DB;
this.pool.set(dbKey, db);
}
return db;
}
}
export const dbPool = new DBPool();
import diagnostics = require("./diagnostics");
diagnostics.init(initOptions);
And web api looks like:
GET("/api/getuser/:id", (req: Request) => {
const user = getUserFromJWT(session.JWT);
const db = dbPool.get({ user });
return db.users.findById(req.params.id);
});
I'm interested in whether the source code correctly instantiates pgp or should be instantiated within the if block inside get method (the line is commented)?
I've seen that pg-promise uses DatabasePool singleton exported from dbPool.js which is similar to my DBPool class, but with the purpose of giving “WARNING: Creating a duplicate database object for the same connection”. Is it possible to use DatabasePool singleton instead of my dbPool singleton?
It seems to me that dbContext (the second parameter in pgp initialization) can solve my problem, but only if it could be forwarded as a function, not as a value or object. Am I wrong or can dbContext be dynamic when accessing a database object?
I wonder if there is a third (better) solution? Or any other suggestion.
If you are troubled by this warning:
WARNING: Creating a duplicate database object for the same connection
but your intent is to maintain a separate pool per user, you can indicate so by providing any unique parameter for the connection. For example, you can include custom property with the user name:
const cn = {
database: 'my-db',
port: 12345,
user: 'my-login-user',
password: 'my-login-password'
....
my_dynamic_user: 'john-doe'
}
This will be enough for the library to see that there is something unique in your connection, which doesn't match the other connections, and so it won't produce that warning.
This will work for connection strings as well.
Please note that what you are trying to achieve can only work well when the total number of connections well exceeds the number of users. For example, if you can use up to 100 connections, with up to 10 users. Then you can allocate 10 pools, each with up to 10 connections in it. Otherwise, scalability of your system will suffer, as total number of connections is a very limited resource, you would typically never go beyond 100 connections, as it creates excessive load on the CPU running so many physical connections concurrently. That's why sharing a single connection pool scales much better.
I have created a Xamarin where I want to query one database on a Azure SQL Server and regarding which result I get back I want to query one of X numbers of certain databases.
So far I have been able to create two different APIs where the first API gets information from the first database.
And I have hardcoded (in the TableController) to use one specific database (in the same SQL Server).
string dbString = "database2";
myContextClass context = new myContextClass(dbString);
This works like a charm. However. I would like to be able to pass which database I want to connect to from my app.
I.e. when calling my mobileservice all I do is this:
this.client = new MobileServiceClient(
Constants.DatabaseURL);
Is there something I can add to this methodcall that will set the database connectionstring in the controller?
You should not be connecting to the database from the mobile App, you should have a backend REST service built for example using Web API and hosted in Azure API Service, this is where the connection to the database will occur, and the connection string will be added to the web.config file which can be easily changed from the Azure portal.
I think you need 2 dbContext instances. Here is an example in the controller how to initialize 1 dbContext. So, I guess, you could have the parameter you want to specify which db you want, and use the main controller or call another controller which is initialized with the other dbContext. (or try overwriting the DomainManager with different context)
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
AppContext context = new AppContext();
DomainManager = new EntityDomainManager<TodoItem>(context, Request);
}
// GET tables/TodoItem
public IQueryable<TodoItem> GetAllTodoItems()
{
return Query();
}
Then you have 2 dbContext instances like this:
public class AppContext : DbContext
{
private const string connectionStringName = "Name=MS_TableConnectionString";
public NeptuneAppContext() : base(connectionStringName)
{
}
where you can specify different connectionStrings.
Hope it helps
I'm seeing a lot of exceptions in the collectionSelfLink when making DocumentDb call -- see image below.
I'm able to connect to DocumentDb and read data but these exceptions concern me -- especially in something that's pretty straight forward like a collectionSelfLink.
Any idea what may be causing them and how to fix them?
Here's the function that's using the selfLink
public async Task<IEnumerable<T>> ReadQuery<T>(string dbName, string collectionId, SqlQuerySpec query)
{
// Prepare collection self link
// IMPORTANT: This is where I'm seeing those exceptions when I inspect the collectionLink. Otherwise, I'm NOT getting any errors.
var collectionLink = UriFactory.CreateDocumentCollectionUri(dbName, collectionId);
var result = _client.CreateDocumentQuery<T>(collectionLink, query, null);
_client.CreateDocumentQuery<T>(collectionLink);
return await result.QueryAsync();
}
And here's the QueryAsync() extension method
public async static Task<IEnumerable<T>> QueryAsync<T>(this IQueryable<T> query)
{
var docQuery = query.AsDocumentQuery();
var batches = new List<IEnumerable<T>>();
do
{
var batch = await docQuery.ExecuteNextAsync<T>();
batches.Add(batch);
}
while (docQuery.HasMoreResults);
var docs = batches.SelectMany(b => b);
return docs;
}
So SelfLink is an internal property that is set by DocumentDB. It cannot be set by the user and will only be populated on resources that have been returned from a call to the server.
The UriFactory code that you are using is construction a link that can be used to execute operations, but it is not a SelfLink.
If you are looking at a SelfLink property on a newly initialized DocumentCollection() object the SelfLink will be null as it has not been persisted on the server yet. This would explain all those errors in debug watch.
I assumed that we should use basicredisclientmanager or pooledredisclientmanager?
I tried this
private void dddddd()
{
for(int i=0;i<=1000;i++)
{
var client = new BasicRedisClientManager(new string[] { "host1", "host2", "host3" }).GetClient();
//do something with client
}
}
This loop runs fine for the first 100 plus but after that, I always got an error "Unknown Command Role"?? What is that and how to fix it? I need help!
I also tried to make a new class called MyRedisMgr and created a static property to create some sort of singleton but it didn't work either.
public BasicRedisClientManager MyMgr = new BasicRedisClientManager(new string[] { "host1", "host2", "host3" });
And then I use it like
for(int i=0;i<=1000;i++)
{
var client = MyRedisMgr.MyMgr.GetClient();
//do something with client
}
Please read the documentation on the proper usage of Redis Client Manager which should only be used as a singleton.
The BasicRedisClientManager doesn't have any connection pooling so every time you call GetClient() you're opening a new TCP connection with the redis-server. Unless you understand the implications you should be using one of the Pooled Redis Client Managers, e.g: RedisManagerPool.
You also need to always dispose the client after its used so that it can either be re-used or the TCP connection disposed of properly.
So your code sample should look like:
//Always use the same singleton instance of a Client Manager
var redisManager = new RedisManagerPool(masterHost);
for(int i=0;i<=1000;i++)
{
using (var redis = redisManager.GetClient())
{
//do something with client
}
}
The "Unknown Command Role" error is due to using an old version of Redis Server. The ROLE command was added in redis 2.8.12 but this API should only be used if your using redis-server v2.8.12+, so you shouldn't be getting this error by default. You can avoid this error by upgrading to either the stable v3.0 or old 2.8 versions of redis-server which has this command.
If you want to continue using an older version, use the INFO command to check what version you're running then tell ServiceStack.Redis what the version is with:
RedisConfig.AssumeServerVersion = 2600; //e.g. v2.6
RedisConfig.AssumeServerVersion = 2612; //e.g. v2.6.12
Given the following code from my Configure method:
OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory(ConfigUtils.GetConnectionString("Oracle:FEConnection"), OracleOrmLiteDialectProvider.Instance);
container.Register<IDbConnectionFactory>(dbFactory)).ReusedWithin(ReuseScope.Request); // <== this does NOT work
// But these work
container.Register<IPreprocessorRepository>(c => new CachedPreprocessorRepository(dbFactory, c.Resolve<ICacheClient>())).ReusedWithin(ReuseScope.Default);
container.Register<IPreprocessor>(c => new DirectApiPreprocessor(c.Resolve<IPreprocessorRepository>(), c.Resolve<IValidator<LeadInformation>>())).ReusedWithin(ReuseScope.Default);
How can I make sure that the dbFactory instanciated is used in other registrations will per request?
Thank you,
Stephen
You can't change the scope of this:
container.Register<IDbConnectionFactory>(dbFactory)
.ReusedWithin(ReuseScope.Request);
Because you're only passing in an instance of an object, and not a factory function that the IOC would need to be able to instantiate instances of the object itself. All the IOC can do in this case is return the instance, making it a singleton.
To be able to change the scope you would need to register a delegate that can create an instance, i.e:
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(...))
.ReusedWithin(ReuseScope.Request);
But you never want to do this with any connection or client factories like IDbConnectionFactory or IRedisClientsManager since they're designed to be used as singletons.
i.e. They're thread-safe singleton factories used to create single client/connection instances:
using (var db = container.Resolve<IDbConnectionFactory>().Open())
{
//...
}
using (var redis = container.Resolve<IRedisClientsManager>().GetClient())
{
//...
}