I'm using EF's Code First approach with MySQL.
I'm wondering if EF in that approach has built in protection against the SQL Injection, or do I have to create SQL string query in the MySqlCommand and add some parameters to be safe from that attacks ?
I think I don't have to but I'd like to be sure about that.
Edit (code snippets example):
MyContext cont = new MyContext();
cont.Comment.AddObject(new Comment { Content = "my string" });
cont.SaveChanges();
or
string query = "INSERT INTO Comment(Content)VALUES(#myVal)";
MySqlCommand comm = new MySqlCommand(query);
comm.CommandType = CommandType.Text;
comm.Parameters.AddWithValue("#myVal", "my string");
...and later execute that query
The 1st approach is much faster to code for me
Your first code is SQL Injection proof.
Anything that you pass to EntityFramework are passed as Command in the inner IDbCommand.
But beware, if you are executing direct query with EntityFramework.
A sentence from MSDN.
Although query composition is possible in LINQ to Entities, it is
performed through the object model API. Unlike Entity SQL queries,
LINQ to Entities queries are not composed by using string manipulation
or concatenation, and they are not susceptible to traditional SQL
injection attacks. "
EF's LINQ to Entities (as used in your first example) takes care of preventing SQL injection attacks.
Related
I am learning JPA with Hibernate, using maven as well. My problem is How can I use input parameters with UPDATE and SET clause in named query ?
#NamedQuery(name = "updateEmailAddress", query = "Update User u set u.email = :email where u.username = :username")
It gives me an error that a parameter can only be used in the WHERE or HAVING clause. I referred several article but still cannot find the proper solution.
In JPA 2.0 and below, parameters are not allowed in the set clause of a named query; only literals. This limitation is lifted if you are using JPA 2.1.
From what I can gather, you are not using JPA 2.1. Hence, I'll give you a couple of ways to sidestep this limitation.
Option 1:
Use the createQuery method and pass a dynamically generated string to the method.
String queryString = generateQueryString(email, username);
entityManager.createQuery(queryString).executeUpdate();
Option 2:
Update the associated entity and merge.
List<User> result = entityManager.createQuery('select u from user u where
u.username = :username').setParameter('username', username).getResultList();
for (User user : result) {
user.setEmail(email);
entityManager.merge(user);
}
Option 3:
Create the query using HQL not JPQL. I haven't tested this nor do I recommend it because you are going behind the entity manager's back.
Query q = sessionFactory.getCurrentSession().createNamedQuery('updateEmailAddress');
q.setParameter('email', email);
q.setParameter('username', username);
q.executeUpdate();
While in fact until JPA 2.1 this was not allowed, you can actually use it because the providers will let you provide parameters in that way (which turns out to be a good thing!).
It seems the JPA providers are not conforming to the spec regarding this validation, and I think is just because it didn't make any sense (you can see in 2.1 it is now permitted). "Why would me make it difficult do developers?"
I am also using EclipseLink 2.3.1 and it is working fine.
The recommended solution
Just disable Eclipse's JPQL query validation.
If the provider accepts it, you should be fine, otherwise you need to conform to the spec. Very simple. Code will be cleaner and it will conform to recent evaluations of the spec.
Just go to: Preferences > Java Persistence > JPA > Errors/Warnings > Queries and Generators > Invalid or incomplete JPQL queries: and Ignore it
Check this article for details:
Conclusion
Hibernate does not follow the specification on this point but one
might guess that the new version of the JPA-spec will allow this
behavior as indicated by the draft JSR. JBoss Tools is probably
validating the query against the JPQL-grammar which is based on the
specification and is therefore showing a validation error.
And this is the resolution:
End remark
After a discussion in out team we decided to keep the current
implementation despite the breach of specification. Changing the
behavior would mean string concatenation or string substitution to
build the query and the current approach is much cleaner. As we see no
indications of a shift in persistence provider or application server
at this stage we believe the gains of keeping the code are larger than
the risks at this point.
Can you try positional parameter and see if it works?
#NamedQuery(name = "updateEmailAddress", query = "UPDATE User u SET u.email = ?1 WHERE u.username = ?2")
//The parameter needs to be passed as
query.setParameter(1, "the_emailaddress");
query.setParameter(2, "the_username");
You must build a query named as follows:
Query query = getEntityManager().createNamedQuery("updateEmailAddress");
query.setParameter("email", "email#test.com");
query.setParameter("username", "emailuser");
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
Sources:
Hibernate 3.6 - DML-style operations
hibernate 4.2 - HQL for UPDATE and DELETE
Hibernate Query examples (HQL)
Hibernate Query Languages
I am thinking of designing a business rule engine which basically generates an EF query from a set of string values stored in a database.
For e.g. I will store the connection string, table name, the where condition predicate, and select predicate as string fields in a db and would like to construct the EF query dynamically. For e.g.
var db = new DbContext(“connectionstring”);
var wherePredicate = Expression.FromString(“p => p.StartDate > new DateTime(2014,5,1))
var selectPredicate = Expression.FromString(“p => p”)
var results = db.Set(“Projects”).Where(wherepredicate).Select(selectPredicate)
For constructing the predicates I can use DynamicExpression or Dynamic LINQ library.
However how do I access db.Set(“Projects”) where Projects is the entity name and apply the where and select predicates? (or something like db[“Projects”].Where().Select).
I tried the non-generic version of the DbContext.Set(Type entityttype) method, however couldn’t figure out how to apply Where and Select predicates to the returned object.
I am trying to avoid generating SQL queries and instead rely on dynamically generated EF code.
This doesn't make much sense. You can create method that will work on string instead of generic type using reflection, but you'd have to return DbSet not DBSet<T>. And on that one you cannot execute LINQ's methods (basically), because there's no type (during compilation). Of course you can do it all the way using reflection, but then, why??? You're loosing 90% of what O/R mapper does for you.
I understand the advantages of using a JPA criteria builder above the Java Persistence Query Language.
Is there an easy way to explain how to build up this kind of queries?
I need a more human readable explanation to build up my queries, this to have a kind of intuitive approach to query my database.
Example:
SQL:
SELECT id,status,created_at from transactions where status='1'
and currency='USD' and appId='123' order by id
Critera Builder with MetaModel:
Map<SingularAttribute<Transaction, ?>, Object> params = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Transaction> r = cq.from(Transaction.class);
Predicate p= cb.conjunction();
for (Map.Entry<SingularAttribute<Transaction, ?>, Object> param: params.entrySet())
p = cb.and(p, cb.equal(r.get(param.getKey()), param.getValue()));
cq.multiselect(r.get(Transaction_.id), r.get(Transaction_.status),
r.get(Transaction_.created_at))
.where(p)
.orderBy(cb.asc(r.get(Transaction_.id)));
List<Tuple> result = em.createQuery(cq).getResultList();
This example was based on another question:
Complex queries with JPA criteria builder
I don't think there's an more clean way to write that kind of query following the standards and not using an hand wrote JPQL query, anyway out of the standard the are many query builders like: query dsl or Torpedo query or Object Query that allow to write query in a more clean way if that can help :)
Criteria query have some advantages of JPQL, such as: type safety, write SQL querias based on Java Programming model and make it portable. The easiest way in which I understand this when I started to work with JPA is think in the main objects that you need to use and their features.
CriteriaBuilder: Any statement that can be done using SQL like functions, reserved works, operations, predicates are part of this class, so builder need to be used to create those and apply them to the criteriaQuery.
CriteriaQuery: Any statement to have as goal to create a formal SQL statement are here, think on this as the boilerplate of the query definition, it have from, select, where, group by and all the statements, so this is the query itself and must be use to determine what you are really looking for from the database.
Now think to do a query you always must to use a Root, this mean select what will be your main table in your query definitions, based on that and helping from CriteriaQuery and CriteriaBuilder objects you can redefine the search to be whatever you want.
I made a SqlDependency service in my application. It works perfectly when I type the queries by hand but I cannot include wildcards (I don't really know why).
For example:
//Using this SqlCommand will work
new SqlCommand("SELECT [employees].[name] FROM [dbo].[employees]", sqlNotificationConn)
//But this one won't
new SqlCommand("SELECT [employees].* FROM [dbo].[employees]", sqlNotificationConn)
//And this one won't either
new SqlCommand("SELECT * FROM [dbo].[employees]", sqlNotificationConn)
So basically, I want to get my DbContext to generate a full SELECT command with every fields it deals with.
In Linq 2 SQL, I used this service using dbContext.GetCommand(.....);
In EF 4.0 (or was it 4.1?), I used dbContext.employee.ToTraceString();
But in EF 4.4, I can't find anything to generate that SELECT query string....
With DbContext (DbQuery) it is as simple as:
query.ToString()
With ObjectContext (ObjectQuery):
((ObjectQuery)query).ToTraceString()
By the way, query can be any expression based on a DbSet (or ObjectSet, respectively). So something like dbContext.employee.Where(e => e.Name == "Gates").ToString() will also show the generated SQL query.
A LINQ statement that forces execution, like ToList(), Single(), FirstOrDefault(), etc, creates a new object and ToString() will return the object's type name.
ToTraceString() is still in EF, same place it always was. However, it's on ObjectQuery, not DbQuery. Having said that, I've never seen the SQL Server provider for EF use *; it always uses discrete fields in SQL.
Could I ask somebody show me the way how to declare the association between two entities 'Record' and 'DictionaryItem' if corresponded tables on the DB level are joined by such interesting rule:
FROM Records R LEFT OUTER JOIN DictionaryItems D
ON SUBSTRING(R.CompositeKey,3,8) = D.DictionaryItemId
P.S. I'm now working with POCO entities.
Linq-to-entities doesn't support Substring. You must either execute SQL directly by calling context.Database.SqlQuery<> or you must use Entity SQL - that would probably require converting DbContext to ObjectContext via IObjectContextAdapter, creating ObjectSet and running ESQL query.