Fluent NHibernate - how to configure for oracle? - oracle

Almost certainly a stupid question but I can't find the answer anywhere.
In the Getting Started tutorial the database is SQLite and so his session factory creation
is done using the SQLiteConfiguration class in the FluentNHibernate.Cfg.Db namespace
Great! But I don't see a Configuration class for using an Oracle database. How do I do this?
Cross-posted to the fluent NH mailing list (with answer)

This works for me. Hope this helps!
private static ISessionFactory CreateSessionFactory()
{
var cfg = OracleClientConfiguration.Oracle9
.ConnectionString(c =>
c.Is("DATA SOURCE=<<NAME>>;PERSIST SECURITY INFO=True;USER ID=<<USER_NAME>>;Password=<<PASSWORD>>"));
return Fluently.Configure()
.Database(cfg)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<CLASS_NAME>().ExportTo(#".\"))
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
private static void BuildSchema(NHibernate.Cfg.Configuration config)
{
// this NHibernate tool takes a configuration (with mapping info in)
// and exports a database schema from it
new SchemaExport(config)
.Create(false, true);
}

Does this helps you?
http://tiredblogger.wordpress.com/2008/12/04/persistanceconfiguration-for-oraclefluent-nhibernate/
Edit: The code mentioned uses the ConnectionStringExpression class which no longer exists in Fluent NHibernate. However, that class isn't used for anything other than holding the OracleConfiguration _config field. You can safely, add the field to the OracleConnectionStringExpression class and remove it.
The remaining issue is that NHibernate will now for some reason look for components that are not in the current build of Oracle.DataAccess. If you want to deal with that you can do what tiredblogger did here.

Related

Entity Framework 7 Interceptor

I Have a Multi-Tenant application and how can I use Interception in Entity Framework 7?
In Entity Framework 6, exists Interception using System.Data.Entity.Infrastructure.Interception, but don't find in version 7 of the Entity Framework.
Here's an example -> https://azure.microsoft.com/en-us/documentation/articles/web-sites-dotnet-entity-framework-row-level-security/
Interception isn't implemented yet in EFCore. It is a backlog item (see https://github.com/aspnet/EntityFramework/wiki/Roadmap)
Although EF Core does not have Interceptors, it is possible to perform QueryFilters to ensure that all queries are filtered by the tenant id.
Gunnar Peipman has a number of articles that can help you understand how to use QueryFilters for a Multi-Tenant scenario.
http://gunnarpeipman.com/2017/08/ef-core-global-query-filters/
I have somewhat some issue.
In EF Core you can use interceptors, here's some sample code that may be of use:
using System.Data.Common;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.DiagnosticAdapter;
public class CommandListener
{
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting")]
public void OnCommandExecuting(DbCommand command, DbCommandMethod executeMethod, Guid commandId, Guid connectionId, bool async, DateTimeOffset startTime)
{
//call security or other methods here.
}
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted")]
public void OnCommandExecuted(object result, bool async)
{
//call security or other methods here.
}
}
In the constructor of your repository you do the hooking
var listener = _context.GetService<DiagnosticSource>();
(listener as DiagnosticListener).SubscribeWithAdapter(new CommandListener());
Now when you query your dbContext e.g.:
_context.employees.Where(...
Then before this query is returned the above methods OnCommandExecuting and OnCommandExecuted are executed.
So you can somewhat imitate the override of SaveChanges in EF Core.
However one important thing to note is that the return result set from the query is not accessible in the OnCommandExecuting and OnCommandExecuted methods.

Debugging Entity Framework SQL statements

I am having a weird pattern of response time when using the Entity Framework for SQL communication.
This is from my web host:
This is from my local server:
It's the increase in response time I am worried about.
I have narrowed the problem down to one single line in code
Nop.Data > EfRepository.cs > public void Insert(T entity) > _entities.Add(entity);
Yes I know this very specific for the NopCommerce, but the point is really that I am looking her for help on how to debug this.
Are there some events I can catch that display the SQL being executed?
Or what other things can I do to find out more what is actually happening in the Entity Framework in that above command.
For debugging EF queries, the easiest thing is to cast the query to ObjectQuery and use ToTraceString:
var query = myContext.MyTable
.Where(r => r.Id == searchId)
.Select(r => r);
Console.WriteLine(((ObjectQuery)query).ToTraceString());
This will show the underlying SQL for the query, and you can run the queries manually to debug why they are slow. Here is the MSDN link:
http://msdn.microsoft.com/en-us/library/system.data.objects.objectquery.totracestring.aspx
If you're trying to get the SQL which is run when you call SaveChanges() on your context, it's not as easy. You could take a look at EFTracingProvider:
http://blogs.msdn.com/b/jkowalski/archive/2009/06/11/tracing-and-caching-in-entity-framework-available-on-msdn-code-gallery.aspx
Or, assuming you use SQL Server, you can go directly to SQL Profiler and capture the T-SQL statements (this is my preferred approach).
In EF6, you can also do this in the constructor of your dbcontext
Example
public BookServiceContext() : base("name=BookServiceContext")
{
// New code:
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
This will log to the console every SQL query EF generates. See this article for more information http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/
Another example might be very helpful for someone.
public class MyDbContext : DbContext
{
private readonly ILoggerFactory _loggerFactory;
public MyDbContext(DbContextOptions<MyDbContext> options, ILoggerFactory loggerFactory) : base(options)
{
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Enable logging
optionsBuilder.UseLoggerFactory(_loggerFactory);
if (System.Diagnostics.Debugger.IsAttached)
optionsBuilder.EnableSensitiveDataLogging();
base.OnConfiguring(optionsBuilder);
}
}

how to replace code that uses now obsolete System.Data.OracleClient namespace classes?

I've made a "generic" program that converts data from a db to another. It uses configuration files to define the conversion. It uses code like this:
static DbProviderFactory _srcProvFactory;
static DbProviderFactory _trgtProvFactory;
public static bool DoConversions()
{
try
{
if (!InitConfig())
return false;
_srcProvFactory = DbProviderFactories.GetFactory(GetConnectionClassTypeByDatabaseType(Preferences.SourceDatabaseType));
_trgtProvFactory = DbProviderFactories.GetFactory(GetConnectionClassTypeByDatabaseType(Preferences.TargetDatabaseType));
using (DbConnection srcCnctn = _srcProvFactory.CreateConnection(),
trgtCnctn = _trgtProvFactory.CreateConnection())
{
srcCnctn.ConnectionString = Preferences.SourceConnectionString;
srcCnctn.Open();
trgtCnctn.ConnectionString = Preferences.TargetConnectionString;
trgtCnctn.Open();
//DO STUFF
}
}
}
Above GetConnectionClassTypeByDatabaseType-method return strings like "System.Data.OracleClient" depending on config file.
The DO STUFF part calls methods like one below (there's many of these) to find out database table column properties from schema. This is needed cause Oracle, SQL server etc. handle these differently.
public static int GetColumnMaxStringLength(DbProviderFactory provFactory, DataRow schemaTableRow)
{
if (provFactory is OracleClientFactory)
{
return Convert.ToInt32(schemaTableRow["LENGTH"]);
}
else if // OTHER OPTIONS
...
throw new Exception(string.Format("Unsupported DbProviderFactory -type: {0}", provFactory.GetType().ToString()));
}
So how this is supposed to be fixed now when the build says these classes are obsolete? This was supposed to be kind of text book solution when I did this (Pro C# 2008 and the
.NET 3.5 Platform). Now I'm baffled.
Thanks in advance & Best Regards - Matti
ODP.NET or any of the other 3rd party ADO.NET driver providers:
ref: Comparison of 3rd Party Oracle .NET Providers

Custom ASP.NET SqlMembershipProvider - handling connection string

I am creating a custom SqlMembershipProvider class to add some enhanced functionality to the base class. I'm getting caught up on handling the connection string, though. How can I read the Connection String Name from the configuration and make that available to the rest of the methods?
Right now I have:
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
_ConnectionStringName = config["connectionStringName"];
}
But in other methods, the _ConnectionStringName variable is null:
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[_ConnectionStringName].ConnectionString)
What is the proper way to store the Connection String Name so it is available globally in my custom membership provider?
Thanks!
ProviderBase will throw a ConfigurationException if there are any entries left in the config collection by the time it get's it so each provider removes it's configuration entries before calling base.Initialize.
The issue, as you have found as a result of this answer is that you must get your values before calling base.Initialize.
Sorry, I missed that at first glance.
The rest of this post is historical and while technically correct misses the salient issue here as enumerated above.
First - try WebConfigurationManager.ConnectionStrings.
WebConfigurationManager handles applying the hierarchy of web.config all the way from your windows\microsoft.net\framework\2.0xxxx\web.config all the way up to your app.
This behaviour is not present in ConfigurationManager, which typically deals with machine.config to app.config.
If this does not solve your problem you must be overwriting the value elsewhere in your code, if indeed _ConnectionStringName is being properly assigned in Initialize.
First, set a breakpoint and ensure that _ConnectionStringName is being set as expected.
Then locate all references to the field and ensure that you do not have a bug.
This is assuming, of course, that _ConnectionStringName is a private field. If it is not, make it so and look for your compile error.
Not sure if this helps, but I was having a similar issue in needing to override the connectionstring in a sub-class of SqlMembershipProvider.
This idea is not my own - I found it in the comments section of this forum posting:
http://forums.asp.net/p/997608/2209437.aspx
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);<br>
string connectionString = //...what you want your connection string to be,
//so config["connectionStringName"]...
// Set private property of Membership provider.
System.Reflection.FieldInfo connectionStringField =
GetType().BaseType.GetField("_sqlConnectionString",
System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.NonPublic);
connectionStringField.SetValue(this, connectionString);
}
My apologies - I've never posted here before, so the formatting may be sub-par!
This is probably 6 months too late to help, but I was able to get the connection string this way:
using System.Web.Configuration;
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
MembershipSection section = config.SectionGroups["system.web"].Sections["membership"] as MembershipSection;
string defaultProvider = section.DefaultProvider;
string connstringName = section.Providers[defaultProvider].ElementInformation.Properties["connectionStringName"].Value.ToString();
string val = config.ConnectionStrings.ConnectionStrings[connstringName].ConnectionString;
This makes the assumption that the default provider has a connection string property - but if you're subclassing SqlMembershipProvider then should always have one, somewhere up the web.config chain (it's defined in the machine.config I believe).
All of this, to add one method to change the username.

Enterprise Library Validation Block - Should validation be placed on class or interface?

I am not sure where the best place to put validation (using the Enterprise Library Validation Block) is? Should it be on the class or on the interface?
Things that may effect it
Validation rules would not be changed in classes which inherit from the interface.
Validation rules would not be changed in classes which inherit from the class.
Inheritance will occur from the class in most cases - I suspect some fringe cases to inherit from the interface (but I would try and avoid it).
The interface main use is for DI which will be done with the Unity block.
The way you are trying to use the Validation Block with DI, I dont think its a problem if you set the attributes at interface level. Also, I dont think it should create problems in the inheritance chain. However, I have mostly seen this block used at class level, with an intent to keep interfaces not over specify things. IMO i dont see a big threat in doing this.
Be very careful here, your test is too simple.
This will not work as you expect for SelfValidation Validators or Class Validators, only for the simple property validators like you have there.
Also, if you are using the PropertyProxyValidator in an ASP.NET page, iI don;t believe it will work either, because it only looks a field validators, not inherited/implemented validators...
Yes big holes in the VAB if you ask me..
For the sake of completeness I decided to write a small test to make sure it would work as expected and it does, I'm just posting it here in case anyone else wants it in future.
using System;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ISpike spike = new Spike();
spike.Name = "A really long name that will fail.";
ValidationResults r = Validation.Validate<ISpike>(spike);
if (!r.IsValid)
{
throw new InvalidOperationException("Validation error found.");
}
}
}
public class Spike : ConsoleApplication1.ISpike
{
public string Name { get; set; }
}
interface ISpike
{
[StringLengthValidator(2, 5)]
string Name { get; set; }
}
}
What version of Enterprise Library are you using for your code example? I tried it using Enterprise Library 5.0, but it didn't work.
I tracked it down to the following section of code w/in the EL5.0 source code:
[namespace Microsoft.Practices.EnterpriseLibrary.Validation]
[public static class Validation]
public static ValidationResults Validate<T>(T target, ValidationSpecificationSource source)
{
Type targetType = target != null ? target.GetType() : typeof(T);
Validator validator = ValidationFactory.CreateValidator(targetType, source);
return validator.Validate(target);
}
If the target object is defined, then target.GetType() will return the most specific class definition, NOT the interface definition.
My workaround is to replace your line:
ValidationResults r = Validation.Validate<ISpike>(spike);
With:
ValidationResults r ValidationFactory.CreateValidator<ISpike>().Validate(spike);
This got it working for me.

Resources