http://www.codeproject.com/Articles/11178/Writing-SQL-queries-in-XML-A-support-intensive-app
ASP.NET - Storing SQL Queries in Global Resource File?
I want to do something like the above link...but it is not working for me..
I have dynamic sql in my project which i want to move to xml. Can some one please help?
I really hope that you saying you want to store "SELECT BookingID from BOOKING WHERE BOOKINGDATE >= {0}" doesn't mean you are planning on writing:
String.Format(query, parameter)
That's a huge security vulnerability.
Edit:
If you really want to go down this route I would suggest Xml like:
<queries>
<query id="getBookingId">
<parameters>
<parameter name="bookingDate" />
</parameters>
<statement>
<!--
SELECT BookingID from BOOKING WHERE BOOKINGDATE >= #bookingDate
-->
</statement>
</query>
</queries>
Then you can have a class:
[XmlElement("query")]
public sealed class Query
{
[XmlAttribute("id")]
public string Id { get; set; }
// other elements/collections
}
You can then deserialize your Xml into a collection of these Query objects. I would recommend doing this once and storing it in an IDictionary somewhere to avoid repeatedly processing an Xml file.
You then have everything you need in each Query object. A collection of parameters and the sql statement - note that you'll have to manually strip the comment characters () out of the statement before using. Again, probably best to do this once at the beginning.
Related
I'm doing quite a big Symfony2 project (unfortunately on a database which structure I cannot modify) and I'm stuck with this:
I have a User entity which contains (amongst other fields) the username field.
I also have a ProfileField entity that corresponds with extra fields for User (like firstname or lastname, favourite color or whatever you would like to ask a user about).
Finally there is the ConfigService, which basically get's a certain value for certain key from the database.
In this particular case it's all about a little config value called 'username_format'. It can take one of 3 values: 'username', 'firstname' or 'firstnamelastname'.
Depending on that value I need to display the properly formatted username. If the value is 'username' - I'm just returning username field value from User entity.
For both 2nd and 3rd case, so when I need to get a custom ProfileField corresponding to that particular user, I've created a simple service (called usernameFormatService) that has ConfigService injected and a method called getNameFromId($userId). The method checks the config value and pulls the correct values for correct user. This all works very nice, but...
I have a blog overview page, in which the formatted username is shown amongst other fields (like title, creation date etc). The Blog entity has manyToOne relationship with User entity. From the mapping I'm getting the username of course, and if 'username_format' config value says that I need firstname for example, I'm pulling it with usernameFormatService inside Twig template and everything is working like it should.
The real problem starts when I need to be able to sort by each column, that means formatted username column also. I'm using Doctrine QueryBuilder to fetch db results, and basically I need the formatted username value somewhere inside User entity (I think) to be able to sort the blogs by this value BEFORE they are pulled from database (why before? pagination).
Can anyone give me at least a hint where to look or how to do it?
Update:
To make it more clear maybe:
Right now the user name that is displayed in overview table is being resolved by usernameFormatService, which uses ConfigService to get 'platform_username_format' config value form the database and, depending on that config value, returns formatted user name.
If it comes to sorting, I need to somehow get that formatted username BEFORE I will actually query the database, so I can get sorted results.
OK, if I understood everything correctly here, I would do something as written below.
Now, what am not sure of is if each user has an option to choose how to view data. Therefore, I hardcoded username_format in service definition but that behavior could be easily altered.
1. ConfigService
I would change your getNameFromId to getNameForUser:
class ConfigService{
private $usernameFormat;
private $repository;
public function __construct($repository, $usernameFormat){
$this->repository = $repository;
$this->usernameFormat = $usernameFormat;
}
public function getNameForUser(User $user){
switch ($this->usernameFormat){
case "username":
return $user->getUsername();
case "firstname":
return $user->getFirstName();
case "firstnamelastname":
reteurn $user->getFirstName() . ' ' . $user->getLastname();
}
}
public function getAllUsers($page){
return $this->repository->getUsers($page, $this->usernameFormat);
}
}
2. ConfigService definition
<parameters>
<parameter key="my.repository.class">Your\Namespace\FooRepository</parameter>
<parameter key="config.service.class">Your\Namespace\Service\ConfigService</parameter>
</parameters>
<services>
<service id="user.repository"
class="%my.repository.class%"
factory-service="doctrine.orm.entity_manager"
factory-method="getRepository">
<argument>YourBundle:User</argument>
</service>
<service id="config.service" class="%config.service.class%">
<argument type="service" id="my.repository.class" />
<argument type="string">username</argument>
</service>
</services>
3. Repository
public UserRepository extends EntityRepository{
public function getUsers($page, $usernameFormat){
$qb = $this->createQueryBuilder('u');
/**
* Rest of quering rules go here: WHERE predicate, ORDERing, pagination
*/
return $qb->getQuery()->getResult();
}
}
Hope this helps a bit...
I have a route:
routes.MapRoute("ResetPasswordConfirm", "reset-password-confirm", new { controller = "Membership", action = "ResetPasswordConfirm" });
and the code
public ActionResult ResetPasswordConfirm(int userid, string key)
{
// ...
}
in my application. So that i have url to be executed like this:
http://localhost/reset-password-confirm?userid=1&key=bla_bla_something
That is absolutely okay, until someone decides to go to
http://localhost/reset-password-confirm
...and look what will happen. ASP.NET will generate predictable error:
The parameters dictionary contains a null entry for parameter 'userid' of non-nullable type 'System.Int32'...
It could be done also by a search robot trying to grab all the possible urls. It's okay, but generates a lot of errors during usage of application in the wild. I want to avoid that, but feel uncomfortable with writing a stub for every possible case for such kind of errors.
Is there any elegant way of doing that? Thanks.
Another way is to handle global errors, just set <customErrors mode="On"></customErrors> on your web.config and create an Error.cshtml on your Shared view folder. MVC3 templates actually include that page.
On the other hand, if you want to be more specific, you should try Action Filters, that's a cool way to handle errors.
[HandleError(View = "YourErrorView", ExceptionType=typeof(NullReferenceException))]
public ActionResult ResetPasswordConfirm(int? userid, string key)
{
if (!userid.HasValue)
throw new NullReferenceException();
// ...
}
Use nullables for your parameters, i.e.:
public ActionResult ResetPasswordConfirm(int? userid, string key)
I'd like to run actual integration tests of my EF4.1 repositories against an in-memory database a la ayende's nhibernate version.
I have a code first model, against a legacy database (old table and column names need mapping to my entites using code configurations).
I'd like to be able to use Sqlite (or other) to:
Generate an in-memory database from my model
Create a DBContext for my model with this in-memory database
I have already in place IoC/DI of a IDBContextFactory which gets constructed with my (Generic) Repositories (also using a GenericRepository pattern)
There's bits and bobs on-line which suggest it should be possible, but not much for code-first approaches. Anyone know if this is possible?
Some snippets of my test library, see // THROWS ERROR marking runtime errors:
public class MyDbContextFactory : IDbContextFactory
{
private static object context;
public object CurrentContext
{
get {
if(context == null)
{
// ?? DOESN'T WORK AS THERE'S NO META DATA
var connBuilder = new EntityConnectionStringBuilder();
connBuilder.Provider = "System.Data.SQLite";
connBuilder.Metadata =
#"res://*/TestEfDb.csdl|res://*/TestEfDb.ssdl|res://*/TestEfDb.msl";
connBuilder.ProviderConnectionString =
ConfigurationManager.ConnectionStrings["DataContext"].Name;
var entConnection = new EntityConnection(connBuilder.ConnectionString);
// THROWS ERROR: sqlite Format of the initialization string does not
// conform to specification starting at index 0
// for connection string "Data Source=:memory:;Version=3;New=True;"
//var entConnection = new EntityConnection
// (ConfigurationManager.ConnectionStrings["DataContext"].Name);
context = new MyDbContext(entConnection);
}
return context;
}
}
}
...
[Test]
public void test_me()
{
var auditRespository = new AuditRepository(new MyDbContextFactory());
auditRespository.GetAll<Audit>();
}
Use SQL Compact 4.0 (download both SqlCE and tools by web platform installer) - EF Code first has direct support for that. The only difference will be that your application will use connection string to big SQL Server:
<add name="MyDbContext"
provider="System.Data.SqlClient"
connectionString=
"Data Source=...;InitialCatalog=...;Integrated Security=SSPI" />
and your tests will use connection string to SQL Compact:
<add name="MyDbContext"
provider="System.Data.SqlServerCe.4.0"
connectionString="Data Source=Database.sdf" />
Take a look at this article: Faking your LINQ provider. It describes how you can hide Entity Framework behind an abstraction, so that you can easily unit test your application, while still allowing to use LINQ (over IQueryable) queries against it in your application code.
Note that this does not completely remove the need of writing integration tests, since you would still need to test the database mapping layer and possibly test whether the chosen LINQ provider is able to execute the LINQ queries.
I am using NHibernate (version 1.2.1) for the first time so I wrote a simple test application (an ASP.NET project) that uses it. In my database I have two tables: Persons and Categories. Each person gets one category, seems easy enough.
| Persons | | Categories |
|--------------| |--------------|
| Id (PK) | | Id (PK) |
| Firstname | | CategoryName |
| Lastname | | CreatedTime |
| CategoryId | | UpdatedTime |
| CreatedTime | | Deleted |
| UpdatedTime |
| Deleted |
The Id, CreatedTime, UpdatedTime and Deleted attributes are a convention I use in all my tables, so I have tried to bring this fact into an additional abstraction layer. I have a project DatabaseFramework which has three important classes:
Entity: an abstract class that defines these four properties. All 'entity objects' (in this case Person and Category) must inherit Entity.
IEntityManager: a generic interface (type parameter as Entity) that defines methods like Load, Insert, Update, etc.
NHibernateEntityManager: an implementation of this interface using NHibernate to do the loading, saving, etc.
Now, the Person and Category classes are straightforward, they just define the attributes of the tables of course (keeping in mind that four of them are in the base Entity class).
Since the Persons table is related to the Categories table via the CategoryId attribute, the Person class has a Category property that holds the related category. However, in my webpage, I will also need the name of this category (CategoryName), for databinding purposes for example. So I created an additional property CategoryName that returns the CategoryName property of the current Category property, or an empty string if the Category is null:
Namespace Database
Public Class Person
Inherits DatabaseFramework.Entity
Public Overridable Property Firstname As String
Public Overridable Property Lastname As String
Public Overridable Property Category As Category
Public Overridable ReadOnly Property CategoryName As String
Get
Return If(Me.Category Is Nothing, _
String.Empty, _
Me.Category.CategoryName)
End Get
End Property
End Class
End Namespace
I am mapping the Person class using this mapping file. The many-to-one relation was suggested by Yads in another thread:
<id name="Id" column="Id" type="int" unsaved-value="0">
<generator class="identity" />
</id>
<property name="CreatedTime" type="DateTime" not-null="true" />
<property name="UpdatedTime" type="DateTime" not-null="true" />
<property name="Deleted" type="Boolean" not-null="true" />
<property name="Firstname" type="String" />
<property name="Lastname" type="String" />
<many-to-one name="Category" column="CategoryId" class="NHibernateWebTest.Database.Category, NHibernateWebTest" />
(I can't get it to show the root node, this forum hides it, I don't know how to escape the html-like tags...)
The final important detail is the Load method of the NHibernateEntityManager implementation. (This is in C# as it's in a different project, sorry about that).
I simply open a new ISession (ISessionFactory.OpenSession) in the GetSession method and then use that to fill an EntityCollection(Of TEntity) which is just a collection inheriting System.Collections.ObjectModel.Collection(Of T).
public virtual EntityCollection< TEntity > Load()
{
using (ISession session = this.GetSession())
{
var entities = session
.CreateCriteria(typeof (TEntity))
.Add(Expression.Eq("Deleted", false))
.List< TEntity >();
return new EntityCollection< TEntity >(entities);
}
}
(Again, I can't get it to format the code correctly, it hides the generic type parameters, probably because it reads the angled symbols as a HTML tag..? If you know how to let me do that, let me know!)
Now, the idea of this Load method is that I get a fully functional collection of Persons, all their properties set to the correct values (including the Category property, and thus, the CategoryName property should return the correct name).
However, it seems that is not the case. When I try to data-bind the result of this Load method to a GridView in ASP.NET, it tells me this:
Property accessor 'CategoryName' on object 'NHibernateWebTest.Database.Person' threw the following exception:'Could not initialize proxy - the owning Session was closed.'
The exception occurs on the DataBind method call here:
public virtual void LoadGrid()
{
if (this.Grid == null) return;
this.Grid.DataSource = this.Manager.Load();
this.Grid.DataBind();
}
Well, of course the session is closed, I closed it via the using block. Isn't that the correct approach, should I keep the session open? And for how long? Can I close it after the DataBind method has been run?
In each case, I'd really like my Load method to just return a functional collection of items. It seems to me that it is now only getting the Category when it is required (eg, when the GridView wants to read the CategoryName, which wants to read the Category property), but at that time the session is closed. Is that reasoning correct?
How do I stop this behavior? Or shouldn't I? And what should I do otherwise?
Thanks!
Setting lazy loading = false in your mapping will solve the error. It would be a better practice though to tell NHibernate in your load query that you want to fetch the child collection of categories eagerly.
For a criteia query something like .SetFetchMode("Categories", FetchMode.Eager) should work.
Here is a link that gives some insight into the so called "n + 1" problem, how lazy loading relates to it, and how NHibernate is meant to be used.
HTH,
Berryl
something like this:
var entities = session
.CreateCriteria<TEntity>()
.SetFetchMode("Categories", FetchMode.Eager)
.Add(Expression.Eq("Deleted", false))
.List< TEntity >();
The problem is that when your entity is lazy loaded. The query only gets the items that it currently needs. So in your case it gets the Person object. Then when you access any linked entities, it fires off another query. It uses proxy objects for this that know about the Session that was used. You are only keeping the Session open for the Load and then you're closing it.
This is actually bad practice in the NHibernate world. You want to keep the session alive for a period known as a unit of work. This gives you a lot of benefits, like caching and lazy loading. Consequently you can disable lazy loading it should work. Although I'd recommend modifying your loader class if at all possiblem
Is it a good idea to store my SQL queries in a global resource file instead of having it in my codebehind? I know stored procedures would be a better solution but I don't have that luxury on this project.
I don't want queries all over my pages and thought a central repository would be a better idea.
Resource files are usually used for localization. But a string is just a string is just a string, and do you really want to be sending any old string in a resource file to your database?
I completely agree with others that you should be using linq or typed datasets, etc. Personally I've only had to resort to text queries a handful of times over the years, and when I do it's usually something like the following:
You set up a small framework and then all you need to do is maintain an Xml file. An single specific xml file is a lot easier to manage and deploy than a resource dll. You also have a well known place (repository) that stores Sql Queries and some metadata about them versus just some naming convention.
Never underestimate the utility of a (simple) class over a string literal. Once you've started using the class you can then add things down the road that you can't (easily) do with just a simple string.
Notepad compiler, so apologies if this isn't 100%. It's just a sketch of how everything interacts.
public static class SqlResource
{
private static Dictionary<string,SqlQuery> dictionary;
public static void Initialize(string file)
{
List<SqlQuery> list;
// deserialize the xml file
using (StreamReader streamReader = new StreamReader(file))
{
XmlSerializer deserializer = new XmlSerializer(typeof(List<SqlQuery>));
list = (List<SqlQuery>)deserializer.Deserialize(streamReader);
}
dictionary = new Dictionary<string,SqlQuery>();
foreach(var item in list )
{
dictionary.Add(item.Name,item);
}
}
public static SqlQuery GetQueryByName(string name)
{
SqlQuery query = dictionary[name];
if( query == null )
throw new ArgumentException("The query '" + name + "' is not valid.");
if( query.IsObsolete )
{
// TODO - log this.
}
return query;
}
}
public sealed class SqlQuery
{
[XmlAttributeAttribute("name")]
public bool Name { get; set; }
[XmlElement("Sql")]
public bool Sql { get; set; }
[XmlAttributeAttribute("obsolete")]
public bool IsObsolete { get; set; }
[XmlIgnore]
public TimeSpan Timeout { get; set;}
/// <summary>
/// Serialization only - XmlSerializer can't serialize normally
/// </summary>
[XmlAttribute("timeout")]
public string Timeout_String
{
get { return Timeout.ToString(); }
set { Timeout = TimeSpan.Parse(value); }
}
}
your xml file might look like
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfSqlQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SqlQuery name="EmployeeByEmployeeID" timeout="00:00:30" >
<Sql>
SELECT * From Employee WHERE EmployeeID = #T0
</Sql>
</SqlQuery>
<SqlQuery name="EmployeesForManager" timeout="00:05:00" obsolete="true" >
<Sql>
SELECT * From Employee WHERE ManagerID = #T0
</Sql>
</SqlQuery>
</ArrayOfSqlQuery>
Ok, I'll try to answer again, now when I have more information.
I would make a query-class that hold all querystrings as shared properties or functions that could be named quite well to be easy to use.
I would look up strongly typed datasets with tableadapters and let the tableadapters handle all queries. When you are used with it you'll never go back.
Just add a dataset to your solution, add a connection, and a tableadapter for a table, then start build all querys (update, select, delete, search and so on) and handle it easy in code behind.
I am in the same situation with some developers preferring to write the queries in the resource file. We are using subsonic and I would prefer to use stored procedures rather then using direct queries.
One option, even though it is bad is to place those queries in a config file and read when needed but this is a very bad option and we may use it if everyone cannot be agreement of using the stored procedures.
You could use the XML config file to associate names with stored procedures too. I'm doing that for a current C# project. The "query" would define what procedure to call.
Since some database engines don't support stored queries, that's not always an option.
Sometimes for small projects, it's OK to use parameterized SQL queries (don't concatenate string). This is especially true for select statements.
Views can also be used for selects instead of stored procedures.
Rob