As answered here, NHibernate includes the SQL of queries as well as parameter values when it encounters an ADO exception. Due to data sensitivity concerns, I need to redact or suppress the values of parameters that were sent to the database so that they don't end up in application logs.
Is there a way to configure NHibernate so that it does not include the parameter values? Or something that I can override to achieve that?
You may use your own custom dialect overriding the BuildSQLExceptionConverter method for yielding a custom NHibernate.Exceptions.ISQLExceptionConverter. (See its default implementation, or see examples in the test project.)
Removing the parameter values here will likely imply some dirty hacking of the Message and/or Sql properties values of the exceptionInfo parameter received by the Convert method.
There is currently no way to prevent NHibernate from formatting the sql parameters values in these properties values.
Using a custom dialect is usually done by extending the one your application is currently using, then configuring it with the dialect setting.
Related
Normally we save an instance into the database simply with inst.save(), but Django uses user.save(using=self._db) in its source code. Also, it uses user.save(update_fields=['last_login']) elsewhere.
This somewhat confuses me. To make things worse, the document for the save() method is extremely simple:
Model.save(force_insert=False, force_update=False,
using=DEFAULT_DB_ALIAS, update_fields=None)[source]
If you want customized saving behavior, you can override this save()
method. See Overriding predefined model methods for more details.
The model save process also has some subtleties; see the sections
below.
It doesn't even contain the explanation of those parameters!
My question is: how do I know when I should use the advanced parameters of save()? If I'm implementing a custom model, I would definitely write user.save().
I've done a couple of experiments myself, like change user.save(using=self._db) to user.save(), and nothing went wrong, but I don't want to be surprised someday. Also, the parameters must be passed for some reasons, right?
The answer is you will know when you need to :)
For now resort to this practice
class MyModel(models.Model):
def save(self,*args, **kwargs):
# do whatever
super(MyModel,self).save(*args,**kwarags)
This way you make sure that you don't accidentally drop any of those mysterious, parameters. But let's try to demystify some of them.
using=self._db
This is to facilitate the use of multible databases in a single django app. Which most apps don't really need.
update_fields
If save() is passed a list of field names in keyword argument
update_fields, only the fields named in that list will be updated.
This may be desirable if you want to update just one or a few fields
on an object. There will be a slight performance benefit from
preventing all of the model fields from being updated in the database
https://docs.djangoproject.com/en/1.11/ref/models/instances/
So the link to the source code is a specific instance where they have used this feature. Quite useful to keep track of when a user logged in for the last time without updating the entire record.
force_insert vs force_update
These tell django to try forcing one or the other operation. Also explained to some extent in https://docs.djangoproject.com/en/1.11/ref/models/instances/
The example of user.save(using=self._db) I believe is redundant when you only have one db, usually defined as "default
. This example simply points out that if you have multiple dbs, you can pass in which of multiple dbs to use when saving.
update_fields is also handy when you keep a reference to an instance for a long time (for example in a middleware) and the data might be changed from somewhere else. In these cases you either have to perform a costly refresh_from_db() on the instance to get the newest data from the database, or when you only want to override specific attributes you can omit the refresh_from_db() call and just use save(update_fields=['attr1', 'attr2']). This will leave all other attributes unchanged in the database except for the ones you specified. If you omit update_fields in this case all values would be overwritten in the database with the values of your cached reference to the instance, leading to information loss.
I use the FieldQuoted attribute in my form class. I noticed that I cannot put this attribute on properties. It only allows it on members/fields. Is there a reason for this? Can this be expanded to allow for properties?
Reason I ask is that I use this class in other places that are property friendly but not member friendly at all (e.g. MVC model binder).
According to Allow Properties instead of fields #67
Yes the library started with fields in 2004 mostly because if you
support properties you must to ensure that are writable, can throw
errors, can slow down assignment with custom code, also the reflection
of .net 1.1 were incredible slow and dynamic code generation for
fields was easy to implement
Later for backward compatibility and lazyness I didn't support
properties, now autoproperties work better thanks to work in this PR
#170
But we must to do the effort and support full properties and try to
make a little impact in the previous code to avoid weird errors, maybe
with new record classes
There seem to have been some changes made against Autoproperties full support #170 but this hasn't been included in the release yet. It only seems to be available on the master branch.
I will be merging this but later I will change the way it works to
avoid use of both autoproperties and fields and also to allow
properties in the general way, but your implementation make the use of
autoproperties a simple task
If you're not happy with using that, I would suggest just creating a separate class for the import/export to mirror your existing class but using fields, as suggested by the accepted answer to Formatting properties with FileHelper. Probably the safest bet for now until they get released.
1) Besides for serialization from an object into a file/memory…… When must we add "[Serializable]" attribute?
2) Why must we add that? Why cannot we directly save the object into some known formation to the .NET library?
3) How can I tell in what sitatuations we must add this attribute? In what conditions?
Many thanks!
1) Besides for serialization from an object into a file/memory…… When must we add "[Serializable]" attribute?
When you want to serialize it, or an object that contains it, directly or indirectly, to any other medium, e.g. a socket, RMI, ...
2) Why must we add that?
Because that's the way they designed it. Security reasons spring to mind: you really don't want a password to be serializable by default for example.
Why cannot we directly save the object into some known formation to the .NET library?
Firstly because Serialization preceded .NET by several years; secondly there are various other ways of accomplishing that, such as SOAP.
3) How can I tell in what situations we must add this attribute? In what conditions?
You're just re-asking the same question here, two more times. You certainly need to do it if you ever get a NotSerializableException naming the class and the exception didn't indicate an inadvertent serialization of something you didn't intend to serialize in the first place.
I'm creating a framework MVC to build my applications. In my application I need to use several DBMS s and I need be prepared for that.
I'm thinking in to use Active Record pattern and it have the "connection" (abstract) associated. The Active Record don't know which DBMS to be used. So, I use Factory Method for have abstract which DBMS been used.
How will I build various queries (CRUD) ? Because each DBMS will need specific query.
I'm think that creating various classes "QueryBuilder" it will can to resolve (one class for each DBMS ).
What's think?
To resolve this issue, you can use DAO Layer Pattern. This pattern hides the database specific details from the client. You can define the interface for CRUD operation which your DAO will implement.
In this way, even your DB changes in future, client of DAO layer don't have to worry about the changes.
Refer below wiki page for more details about this pattern.
http://en.wikipedia.org/wiki/Data_access_object
I assume the intent is to insulate the various ActiveRecord objects from the SQL syntax variances between the DBs?
You didn't define what you exacty intended with a design for your query bulder, but I've done once with methods like AddSelection(colName), AddCriteria(colName, ComparisonEnum, value), etc. If that is your approach then if your queries are small/simple enough then a query builder would work. BUT as soon as you need the ability to build complex joins or inner subqueries then you may hit a wall with that approach.
If you need to handle arbitrarily difficult queries then another option is to create a converter or translator. If you were to define a canonical query format, then each DBMS-specific convert would know how to convert from that canonical format to the DB-specific syntax. You've really got to need this functionality to make it worth the effort though.
And finally, your other appraoch is to subclass the ActiveRecord for each DB. So if you have an EmployeeRecord class you can subclass it with OracleEmployeeRecord, MySqlEmployeeRecord, MsSqlServerEmployeeRecord, and the like. Then use an abstract factory to create the appropriate ActiveRecord objects.
we are currently evaluating whether nHibernate supports the requirements for our project. We share the database with another application so that we are not completely free as regards changes to the schema.
Some columns are filled with unique and consecutive numbers (e.g. for invoices). The next number is determined by a stored procedure that also implements a locking algorithm so that the numbers are guaranteed to be consecutive.
On the one hand we could define a trigger on the respective tables that sets the value for the column when an empty or special value is provided. This would require changing the existing database definition - though it might be the most reliable way to implement this.
In order to avoid the change of the database definition we are trying to solve this in the nHibernate ORM. We've first tried to implement a user type that calls the stored procedure in NullSafeSet if an empty value is provided. Unfortunately, the connection and transaction of the provided command are not set yet when NullSafeSet is called.
How can we solve this with nHibernate?
Thanks in advance,
Markus
If you decide to go with trigger route, then you'll need to add generated attribute to your property mapping.
Generated properties are properties which have their values generated
by the database. Typically, NHibernate applications needed to Refresh
objects which contain any properties for which the database was
generating values. Marking properties as generated, however, lets the
application delegate this responsibility to NHibernate. Essentially,
whenever NHibernate issues an SQL INSERT or UPDATE for an entity which
has defined generated properties, it immediately issues a select
afterwards to retrieve the generated values.
Aside from that, I'm not quite sure how would you call stored procedure from NHibernate issued INSERT, without adding a trigger or default constraint on column.
Edit
Looks like NHibernate has a notion of class persisters, through the interface IEntityPersister. Maybe you could hack something out from that.
The persister attribute lets you customize the persistence strategy
used for the class. You may, for example, specify your own subclass of
NHibernate.Persister.EntityPersister or you might even provide a
completely new implementation of the interface
NHibernate.Persister.IClassPersister that implements persistence via,
for example, stored procedure calls, serialization to flat files or
LDAP. See NHibernate.DomainModel.CustomPersister for a simple example
(of "persistence" to a Hashtable).
You could start from NHibernate's source.
If you have the ability to add triggers to database, that would probably be the best, straightforward way, without investing too much time to fight with NHibernate's internals.