With reference to Point connectionstring in dbml to app.config
how would you replace the connection name in the partial class with parameter so that you could switch connection strings?
If you are using entity framework then you can use this class
public static void ChangeDatabase(
this DbContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "",
string sqlConnectionString = "")
/* this would be used if the
* connectionString name varied from
* the base EF class name */
{
try
{
// use the const name if it's not null, otherwise
// using the convention of connection string = EF contextname
// grab the type name and we're done
var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
? source.GetType().Name
: configConnectionStringName;
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
// init the sqlbuilder with the full EF connectionstring cargo
var sqlCnxStringBuilder = new SqlConnectionStringBuilder
(entityCnxStringBuilder.ProviderConnectionString);
if (string.IsNullOrEmpty(sqlConnectionString))
{
// only populate parameters with values if added
if (!string.IsNullOrEmpty(initialCatalog))
sqlCnxStringBuilder.InitialCatalog = initialCatalog;
if (!string.IsNullOrEmpty(dataSource))
sqlCnxStringBuilder.DataSource = dataSource;
if (!string.IsNullOrEmpty(userId))
sqlCnxStringBuilder.UserID = userId;
if (!string.IsNullOrEmpty(password))
sqlCnxStringBuilder.Password = password;
// set the integrated security status
sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;
sqlConnectionString = sqlCnxStringBuilder.ConnectionString;
}
// now flip the properties that were changed
source.Database.Connection.ConnectionString
= sqlConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
and call this class using following
dbContext = new ORM.CustomyzerEntities();
this._destDBContext.ChangeDatabase(
sqlConnectionString: connectionstringname);
here replace connectionstringname with your connection string
Related
I need to get a NEXTVAL from a SEQUENCE in an Oracle database. The modelbuilder does have a
builder.HasSequence("TABLE_SEQ");
But I have no clue on how to use that. The only way I can think of is scalar executing a raw SQL to retrieve the next value. Is that the way to go or are there better ways to do this?
I've found several posts that say I should use context.Database.SqlQuery() but in my solution that is missing. Do I need to add a library to get this functionality for EF 6.0?
Examples I found:
Example 1:
public int GetNewCertificateTradeRequestIdentity()
{
using var command = _context.Database.GetDbConnection().CreateCommand();
command.CommandText = "SELECT ts.seq_certificate_trade_request.NEXTVAL FROM DUAL";
_context.Database.OpenConnection();
using var reader = command.ExecuteReader();
reader.Read();
return reader.GetInt32(0);
}
Example 2:
users = await context.Database.SqlQuery<User>("Select * from User", new object[] { }).ToListAsync();
Both the _context.Database.GetDbConnection() context.Database.SqlQuery<x> are missing. Where can I find them?
Ok, in EF6 you have the context.Database.GetDbConnection().CreateCommand(). With that command you can execute a query on the database and receive the result. I've also found a solution for getting the tablename from the EF6 Metadata and added an extension method to handle that. Now I can do the the following:
private Tijdverantwoording Create(decimal? mdwid, decimal? deelprjid, Datum? date)
{
if (mdwid == null || deelprjid == null || date == null) throw new ArgumentNullException();
Weekstaatstatus weekstaatStatus = _WeekstaatStatusService.GetOrCreate(mdwid.Value, date.Jaarweekcode, WeekStaatStatussen.InBewerking, DateTime.Now);
var tijdverantwoording = new Tijdverantwoording
{
Tijdverantwoordingid = GetId<Tijdverantwoording>(), // <= Generate id
Mdwid = mdwid.Value,
Deelprjid = deelprjid.Value,
Datum = date.DagDatum,
Syncstatus = (decimal)SyncStatuses.InBewerking,
Syncdate = DateTime.Now.Date,
Weekstaatstatusid = weekstaatStatus.Weekstaatstatusid
};
_modelContext.Tijdverantwoordingen.Add(tijdverantwoording);
return tijdverantwoording;
}
The base class used for a service.
using Microsoft.EntityFrameworkCore;
using MyProjects.Core.Extensions;
using MyProjects.Core.Model;
namespace MyProjects.Core.Services
{
public class ServiceBase
{
private ModelContext? _modelContext;
public ServiceBase(ModelContext modelContext)
{
_modelContext = modelContext;
}
public decimal GetId<T>()
where T : class
{
var command = _modelContext.Database.GetDbConnection().CreateCommand();
var tableName = _modelContext.TableName(typeof(T));
command.CommandType = System.Data.CommandType.Text;
command.CommandText = $"SELECT {tableName}_SEQ.NEXTVAL FROM DUAL";
_modelContext.Database.OpenConnection();
try
{
var result = (decimal?)command.ExecuteScalar();
return result.Value;
}
finally
{
_modelContext.Database.CloseConnection();
}
}
}
}
And the extension method
using Microsoft.EntityFrameworkCore;
namespace MyProjects.Core.Extensions
{
public static class DatabaseExtensions
{
public static string? TableName(this DbContext context, Type type)
{
var entityType = context.Model.FindEntityType(type);
return entityType?.GetTableName() ?? throw new NullReferenceException($"Can't find name for type {type.Name}");
}
}
}
I am writing a webAPI unittest that have several test call for each method in the class. I am using UseInMemoryDatabase to create a database and loading test data.
I was getting the following error between each test method
The instance of entity type 'AppSettings' cannot be tracked because another instance with the same key value for {'myId '} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached
I added context.Database.EnsureDeleted(); and that removed the error for the Get method but it was still throwing the error in the delete and update unit test.
I can't figure how to removed this error for delete and update when I run all the test methods at once.
Any help is appreciated.
private MyDBContext context;
[TestInitialize]
public void SetUp()
{
var options = new DbContextOptionsBuilder<MyDBContext>()
.UseInMemoryDatabase(databaseName: "MyDB")
.Options;
context = new CACIDBContext(options);
context.Database.EnsureDeleted(); // this removed the error between the several GET test methods. but not the delete,update
context.AppSettings.Add(new AppSettings { myId = 1, MyName = "test1", MyValue = "test1" });
context.AppSettings.Add(new AppSettings { myId = 2, MyName = "test2", MyValue = "test2" });
context.AppSettings.Add(new AppSettings { myId = 3, MyName = "test3", MyValue = "test3" });
context.SaveChanges();
}
[TestMethod]
public void GetSettings()
{
var logger = new Mock<ILogger<SettingsRepository>>();
var caciDbContent = new Mock<CACIDBContext>();
sRepository settingRepository = null;
settingRepository = new sRepository (context, logger.Object);
List<AppSettings> settings = settingRepository.GetSettings().ToList();
Assert.AreEqual(3, settings.Count);
}
[TestMethod]
public void RemoveSetting()
{
var logger = new Mock<ILogger<sRepository>>();
var caciDbContent = new Mock<CACIDBContext>();
sRepository sRepository = null;
sRepository = new sRepository (context, logger.Object);
// test Get By AppSettingName
bool result = sRepository.RemoveSetting(new AppSettings { myId = 3, MyName = "test3", MyValue = "test3");
Assert.AreEqual(true, result);
}
Here is my c# code
public bool RemoveSetting(AppSettings setting)
{
try
{
myDbContent.AppSettings.Remove(setting);
}
catch (Exception ex)
{
logger.LogError($"Failed to removfe an existing appsetting: {ex}");
throw ex;
}
return (myDbContent.SaveChanges() > 0 ? true : false);
}
Adding the following line helped in my case, which is similar to yours.
context.ChangeTracker.Clear()
It is only available for EF Core 5.0 though. Source: Microsoft Docs
Hey i am trying to create a class instance, which is immutable object.
So i was thinking to use proxies.
I want each time a developer will try to change the object properties,
a new object will be deep cloned from the current object.
and the result will be this new object with the changes.
its important the class proto will stay available.
Example:
class Men{
constructor(name){
this.schema = {prop: {innerProp:{}}};
this.name = name;
}
set newName(name){
this.name = name;
}
}
var handler = {
set (target, key, value) {
target = new Proxy(_.cloneDeep(target), this);
target[key] = value;
return target // Return the new obj with the change
}
};
let jeson = new Men("jeson");
let jesonProxy = new Proxy(jeson, handler);
// Taking the new jeson proxy with the change
let newJesonProxy = (jesonProxy.schema = {newProp: {newInnerProp: {}}});
Thanks in advance.
No, you cannot use a proxy for this, and setters not either. They do not allow you to change the result of the assignment. Use an ordinary method for creating the changed instances, and simply freeze the objects.
class Man {
constructor(name) {
this.schema = {prop: {innerProp:{}}};
this.name = name;
Object.freeze(this);
}
withName(name) {
return new this.constructor(name);
}
}
const x = new Man("");
const y = x.withName("jeson");
I am using Xamarin Forms to develop an app and using SQlite to store the user details. Just started with windows(Windows 10). Does SQLite has support for UWP, I have referred some sites and its saying it does support. but when I am trying, the connection is always null.
The code i am using:
public SQLite.Net.SQLiteConnection GetConnection()
{
var sqliteFilename = "Sample.db3";
string path = Path.Combin(ApplicationData.Current.LocalFolder.Path, sqliteFilename);
if (!File.Exists(path))
{
File.Create(path + sqliteFilename);
}
var plat = new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT();
var conn = new SQLite.Net.SQLiteConnection(plat,path);
return conn;
}
}
Any help or suggestion would be much appreciated.
Note: I have installed the SQLite.Net-PCL and added reference to SQLite for Universal App Platform
Inside your App.cs I have a static variable called:
public static LocalDatabase Database { get; private set; }
public App()
{
Database = new LocalDatabase();...
}
And then you can access your Database class on any place of your controller like: App.Database
For reference LocalDatabase class will contain:
public class LocalDatabase
{
static readonly object locker = new object ();
static SQLiteConnection database;
string DatabasePath {
get {
const string sqliteFilename = "LocalDatabaseSQLite.db3";
#if __IOS__
string documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal); // Documents folder
string libraryPath = Path.Combine (documentsPath, "..", "Library"); // Library folder
var path = Path.Combine (libraryPath, sqliteFilename);
#else
#if __ANDROID__
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
#else
// WinPhone
var path = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, sqliteFilename); ;
#endif
#endif
return path;
}
}
public LocalDatabase ()
{
database = new SQLiteConnection (DatabasePath);
database.CreateTable<UserSQLModel> ();
//All your create tables...
}
}
I was wondering the best way of accessing the a user's AuthSession from within a custom validator we have hooked up via the servicestack's fluent-validation API hooks. Basically, the requirements are forcing us to access the database through this validator using a class called "DocNumberValidator ". The user's Id is saved into session when they authenticate, down the line we need this information to complete a successful SQL query. How does one access this session information (see below....). The IoC container does not have reference to the AuthSession?
I guess the question is, how does someone pass the necessary session value into a class invoked by SS validation framework?
Sample Code :
public class MyValidator : AbstractValidator<Statuses>
{
public IDocNumberValidator DocNumberValidator { get; set; }
public StatusesValidator()
{
RuleFor(s => s.DocNumber)
.Must(docNum => this.DocNumberValidator.Validate(docNum))
.WithMessage("Document Number is invalid.")
.WithErrorCode("S-001");
}
}
public class DocNumberValidator : IDocNumberValidator
{
public IDbConnectionFactory Db { get; set; }
public bool Validate(string docNum)
{
var isFound = false;
this.Db.Run(conn =>
{
var sql = "SELECT COUNT([docNumber]) FROM [TABLE] WHERE [docNumber] = #DocNum AND [UserId] = #UserID";
var cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
cmd.Parameters.Add(new SqlParameter("#DocNum", docNum));
cmd.Parameters.Add(new SqlParameter("#UserID", ????????)); // how does one get access to saved users session here
int cnt = (int) cmd.ExecuteScalar();
if (cnt == 1)
isFound = true;
});
return isFound;
}
}
Not really sure this is the best way to do it. Open to suggestions.
Use SessionFeature.GetSessionKey() to get the session key
Add public ICacheClient CacheClient { get; set; } to the validator.
Will be injected by IoC container
Get the AuthUserSession (or whatever type you're using) from the
cache using the key
Added into your example
public class DocNumberValidator : IDocNumberValidator
{
public IDbConnectionFactory Db { get; set; }
public ICacheClient CacheClient { get; set; }
public bool Validate(string docNum)
{
var isFound = false;
var sessionKey = SessionFeature.GetSessionKey();
var user = CacheClient.Get<AuthUserSession>(sessionKey); //Use whatever class you stored in the session
this.Db.Run(conn =>
{
var sql = "SELECT COUNT([docNumber]) FROM [TABLE] WHERE [docNumber] = #DocNum AND [UserId] = #UserID";
var cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
cmd.Parameters.Add(new SqlParameter("#DocNum", docNum));
cmd.Parameters.Add(new SqlParameter("#UserID", user.UserAuthId)); // user whatever property you need access to
int cnt = (int) cmd.ExecuteScalar();
if (cnt == 1)
isFound = true;
});
return isFound;
}
}