I have a stored procedure that has many parameters and I've been using the following to return the results:
db.Database.SqlQuery<GetListCamera_Result>("Camera.sp_get_list_camera #room_name, #disk_status,
#signal_loss_reason, #department_id , #sortColumnName, #sortDirection, #start, #length",
new SqlParameter("room_name", room_name),
new SqlParameter("disk_status", disk_status),
new SqlParameter("department_id", department),
new SqlParameter("signal_loss_reason", reason),
new SqlParameter("sortColumnName", sortColumnName),
new SqlParameter("sortDirection", sortDirection),
new SqlParameter("start", start),
new SqlParameter("length", length)).ToList();
I saw one of my senior using these much more cleaner than mine:
db.Database.SqlQuery<GetLiquidbooks_Result>("sp_get_liquidbooks {0}, {1}, {2}, {3}, {4}",
new object[] { LiquidCode, LibID, LocPrefix, LocID, UserID }).ToList();
What are the differences and is there anything I need to be aware of if I'm switching to his
I think yours is a much safer way. However, if you'd like to make it simpler, you can refer to this article, you don't have to initialize a SqlParameter instance, but the #p1 #p2 syntax is still essential. In the first section of the article, it also mentions that this care should be taken.
AFAIK, SqlQuery doesn't prevent SQL Injection, which means if I pass the DROP command into your second sample, the table may be deleted permanently. Therefore, the one which the senior wrote might expose potential security risks, you should make sure that you use parameters in your query in the correct way to guard against such attacks.
About the second sample, consider using ObjectContext.ExecuteStoreQuery<T>(), it allows you to pass the query string with {0} {1} syntax and object array as the parameter into the method. This method actually invokes CreateStoreCommand which transforms your query and objects into a parameterized query. But SqlQuery seems not.
FYI:
ExecuteStoreQuery source code - You can take a look at this method to get deep into how it works.
SqlQuery source code - As aforementioned, I rechecked the source code, and I couldn't find any codes that help to turn it into parameterized SQL
Related
I have the following code
PagedResultList res = myService.getPage(paginateParams, ...)
println res.size() // returns 2
println res.getTotalCount() // returns 1
getPage looks like:
def criteria = MyDomain.createCriteria()
criteria.list(max: paginateParams.max, offset: paginateParams.offset) { // max is 10, offset is 0, sortBy is updatedAt and sortOrder is desc
eq('org', org)
order(paginateParams.sortBy, paginateParams.sortOrder)
}
why do the two method return different values? The documentation doesn't explain the difference, but does mention that getTotalCount is for number of records
currently on grails 2.4.5
edits:
println on res prints out:
res: [
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a,
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a]
Yes, res has a SINGLE object twice - that's the bug I'm trying to fix. How do I know that? I have an primary key on MyDomain's ID, and when I inspect the database, it's also showing one record for this particular org (see my criteria)
edit 2: I found this comment (http://docs.grails.org/2.4.5/ref/Domain%20Classes/createCriteria.html)
listDistinct If subqueries or associations are used, one may end up
with the same row multiple times in the result set. In Hibernate one
would do a "CriteriaSpecification.DISTINCT_ROOT_ENTITY". In Grails one
can do it by just using this method.
Which, if I understand correctly, is their way of saying "list" method doesn't work in this scenario, use listDistinct instead but then they go on to warn:
The listDistinct() method does not work well with the pagination
options maxResult and firstResult. If you need distinct results with
pagination, we currently recommend that you use HQL. You can find out
more information from this blog post.
However, the blog post is a dead link.
Related: GORM createCriteria and list do not return the same results : what can I do?
Not related to actual problem after question edited but this quote seems useful
Generally PagedResultList .size() perform size() on resultList property (in-memory object represent database record), while .getTotalCount() do count query against database. If this two value didn't match your list may contain duplicate.
After viewing related issues (GORM createCriteria and list do not return the same results : what can I do?) I determined that there were several approaches:
Use grails projection groupBy('id') - doesn't work b/c i need the entire object
USe HSQL - Domain.executeQuery - actually this didn't work for my scenario very well because this returns a list, whereas criteria.list returns a PagedResultList from which I previously got totalCount. This solution had me learning HSQL and also made me break up my existing logic into two components - one that returned PagedResultList and one that didn't
Simply keep a set of IDs as I process my PagedResultList and make sure that I didn't have any duplicates.
I ended up going with option 3 because it was quick, didn't require me to learn a new language (HSQL) and I felt that I could easily write the code to do it and I'm not limited by the CPU to do such a unique ID check.
I am new to learning and understanding how Hydration works, just wanted to point that out first. I'm currently able to Hydrate Select and Insert queries without any problems.
I am currently stuck on trying to Hydrate Update queries now. In my entity I have setup the get/set options for each type of column in my database. I've found that the ObjectProperty() Hydrator works best for my situation too.
However whenever I try to update only a set number of columns and extract via the hydrator I am getting errors because all the other options are not set and are returning null values. I do not need to update everything for a particular row, just a few columns.
For example in my DB Table I may have:
name
phone_number
email_address
But I only need to update the phone_number.
$entity_passport = $this->getEntityPassport();
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => '1'
));
This returns an error because setName() and setEmailAddress() are not included in this update and the query returns that the values cannot be null. But clearly when you look at the DB Table, there is data already there. The data that is there does not need to be changed either, only in this example does the PrimaryPhone() number.
I've been looking and reading documentation all over the place but I cannot find anything that would explain what I am doing wrong. I should note that I am only using Zend\Db (Not Doctrine).
I'm assuming I've missed something someplace due to my lack of knowledge with this new feature I'm trying to understand.
Perhaps you don't Hydrate Update queries... I'm sort of lost / confused. Any help would be appreciated. Thank you!
I think you're having a fundamental misconception of hydration. A hydrator simply populates an entity object from data (hydrate) and extracts data from an entity object (extract). So there are no separate hydrators for different types of queries.
In your update example you should first retrieve the complete entity object ($entity_passport) and then pass it to the TableGateway's update method. You would retrieve the entity by employeeid, since that's the condition you're using to update. So something like this:
$entity_passport = $passportMapper->findByEmployeeId(1);
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => $entity_passport->getId()
));
This is assuming you have some sort of mapper layer. Otherwise you could use your passport TableGateway (I assume that's what getTablePassport() returns, no?).
Otherwise, if you think retrieving the object is too much overhead and you just want to run the query you could use just a \Zend\Db\Sql\Sql object, ie:
$sql = new \Zend\Db\Sql\Sql($dbAdapter);
$update = $sql->update('passport')
->set(array('primary_phone' => $entity_passport->getPrimaryPhone()))
->where(array('employeeid' => $employeeId));
Edit:
Maybe it was a mistake to bring up the mapper, because it may cause more confusion. You could simply use your TableGateway to retrieve the entity object and then hydrate the returned row:
$rows = $this->getTablePassport()->select(array('employeeid' => 1));
$entity_passport = $this->getHydrator($rows->current());
[...]
Edit 2:
I checked your gist and I noticed a few things, so here we go:
I see that your getTablePassport indeed does return an object which is a subclass of TableGateway. You have already set up this class for it to use a HydratingResultset. This means you don't need to do any manual hydrating when retrieving objects using the gateway.
You also already implemented a Search method in that same class, so why not just use that? However I would change that method, because right now you're using LIKE for every single column. Not only is it very inefficient, but it will also give you wrong results, for example on the id column.
If you were to fix that method then you can simply call it in the Service object:
$this->getTablePassport->Search(array('employeeid' => 1));
Otherwise you could just implement a separate method in that tablegateway class, such as
public function findByEmployeeId($employeeId)
{
return $tableGateway->select(array('employeeid' => $employeeId));
}
This should already return an array of entities (or one in this specific case). P.S. make sure to debug and check what is actually being returned when you retrieve the entity. So print_r the entity you get back from the PassportTable before trying the update. You first have to make sure the retrieval code works well.
I'd like to pass in parameters into a query so that I can use relationship properties in CreateUnique. I'd prefer to use the parameters rather than just doing a string format so that it can protect (Am I right in aassuming parameters are cypher injeciton protected?) against cypher injection.
var query = client.Cypher.Start(
new CypherStartBitWithNodeIndexLookup("left", AUTOINDEX, PrimaryIndexKey, uname),
new CypherStartBitWithNodeIndexLookupWithSingleParameter("right", AUTOINDEX, luceneQuery)
).CreateUnique("left-[r:Installed {DeviceId:{DeviceId},OS:{OS}}]->right").Return<Software>("right");
Update: It was a simple addition in the end so I just went ahead and added it. As of 1.0.0.517, the proposal linked to below is now implemented and available on NuGet.
Your query can be:
var query = client
.Cypher
.Start(
new CypherStartBitWithNodeIndexLookup("left", AUTOINDEX, PrimaryIndexKey, uname),
new CypherStartBitWithNodeIndexLookupWithSingleParameter("right", AUTOINDEX, luceneQuery)
)
.CreateUnique("left-[r:Installed {DeviceId:{DeviceId},OS:{OS}}]->right")
.WithParam("DeviceId", 123)
.WithParam("OS", "Windows 8")
.Return<Software>("right");
You can't do this in a nice way right now.
Yes, Cypher parameters are all safe from injection. We pass them across the wire in an entirely different construct that keeps them separate from the query text. In Neo4j, they are stored independently of the query's execution plan.
I've opened an issue at https://bitbucket.org/Readify/neo4jclient/issue/66/support-custom-parameters-in-cypher-fluent, with a proposed syntax, so that we can implement it. If you review the proposal and collaborate over there, we can get this in pretty quickly.
As a workaround, you could probably do:
var query = client
.Cypher
.Start(
new CypherStartBitWithNodeIndexLookup("left", AUTOINDEX, PrimaryIndexKey, uname),
new CypherStartBitWithNodeIndexLookupWithSingleParameter("right", AUTOINDEX, luceneQuery)
)
.CreateUnique("left-[r:Installed {DeviceId:{DeviceId},OS:{OS}}]->right")
.Return<Software>("right")
.Query;
query.QueryParameters.Add("DeviceId", 123);
query.QueryParameters.Add("OS", "Windows 8");
var results = client.ExecuteGetCypherResults<Software>(query);
I wrote that code right here in the answer box though, and haven't tested it, and it's horrible, and ugly, and I'd kind of like you to not use it.
I'm working on an application at the moment in ASP.NET MVC which has a number of look-up tables, all of the form
LookUp {
Id
Text
}
As you can see, this just maps the Id to a textual value. These are used for things such as Colours. I now have a number of these, currently 6 and probably soon to be more.
I'm trying to put together an API that can be used via AJAX to allow the user to add/list/remove values from these lookup tables, so for example I could have something like:
http://example.com/Attributes/Colours/[List/Add/Delete]
My current problem is that clearly, regardless of which lookup table I'm using, everything else happens exactly the same. So really there should be no repetition of code whatsoever.
I currently have a custom route which points to an 'AttributeController', which figures out the attribute/look-up table in question based upon the URL (ie http://example.com/Attributes/Colours/List would want the 'Colours' table). I pass the attribute (Colours - a string) and the operation (List/Add/Delete), as well as any other parameters required (say "Red" if I want to add red to the list) back to my repository where the actual work is performed.
Things start getting messy here, as at the moment I've resorted to doing a switch/case on the attribute string, which can then grab the Linq-to-Sql entity corresponding to the particular lookup table. I find this pretty dirty though as I find myself having to write the same operations on each of the look-up entities, ugh!
What I'd really like to do is have some sort of mapping, which I could simply pass in the attribute name and get out some form of generic lookup object, which I could perform the desired operations on without having to care about type.
Is there some way to do this to my Linq-To-Sql entities? I've tried making them implement a basic interface (IAttribute), which simply specifies the Id/Text properties, however doing things like this fails:
System.Data.Linq.Table<IAttribute> table = GetAttribute("Colours");
As I cannot convert System.Data.Linq.Table<Colour> to System.Data.Linq.Table<IAttribute>.
Is there a way to make these look-up tables 'generic'?
Apologies that this is a bit of a brain-dump. There's surely imformation missing here, so just let me know if you'd like any further details. Cheers!
You have 2 options.
Use Expression Trees to dynamically create your lambda expression
Use Dynamic LINQ as detailed on Scott Gu's blog
I've looked at both options and have successfully implemented Expression Trees as my preferred approach.
Here's an example function that i created: (NOT TESTED)
private static bool ValueExists<T>(String Value) where T : class
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
Expression value = Expression.Equal(Expression.Property(pe, "ColumnName"), Expression.Constant(Value));
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(value, pe);
return MyDataContext.GetTable<T>().Where(predicate).Count() > 0;
}
Instead of using a switch statement, you can use a lookup dictionary. This is psuedocode-ish, but this is one way to get your table in question. You'll have to manually maintain the dictionary, but it should be much easier than a switch.
It looks like the DataContext.GetTable() method could be the answer to your problem. You can get a table if you know the type of the linq entity that you want to operate upon.
Dictionary<string, Type> lookupDict = new Dictionary<string, Type>
{
"Colour", typeof(MatchingLinqEntity)
...
}
Type entityType = lookupDict[AttributeFromRouteValue];
YourDataContext db = new YourDataContext();
var entityTable = db.GetTable(entityType);
var entity = entityTable.Single(x => x.Id == IdFromRouteValue);
// or whatever operations you need
db.SubmitChanges()
The Suteki Shop project has some very slick work in it. You could look into their implementation of IRepository<T> and IRepositoryResolver for a generic repository pattern. This really works well with an IoC container, but you could create them manually with reflection if the performance is acceptable. I'd use this route if you have or can add an IoC container to the project. You need to make sure your IoC container supports open generics if you go this route, but I'm pretty sure all the major players do.
I have realized that I have a very large method, which creates SqlParameter objects and adds them to SqlCommand (cmd). For instance:
SqlParameter itemType = new SqlParameter
{
ParameterName = "ItemType",
Direction = ParameterDirection.Input,
SqlDbType = SqlDbType.Int,
Value = (int)item.ItemType
};
cmd.Parameters.Add(itemType);
A stored procedure has a lot of parameters by design and the design cannot be changed.
I do not like to have several pagedowns of code to create the parameters. It is hard to read/support. Of course I can use regions here, but the question is about the code.
Do you have any ideas how can I improve my code?
Currently, I see only one way here: I need to use custom attributes to specify parameter name, direction and db type for each item property. In this case, I need to use reflection and I am not sure that it is the best choice.
That do you think?
Thank you.
Another way to do this is to make the SqlCommand a member field of the class, and have a member method to initialize it.
This is similar to the code that Visual Studio generates when you create a Component, then drag a SqlCommand onto the design surface. If you configure the SqlCommand with a parameterized query or stored procedure with parameters, then it will generate code to create the SqlParameter objects and add them to the Parameters property.
To use thie SqlCommand later in your code, you would do:
m_Command.Parameters["#ParamName"].Value = value;
Erland Sommerkog's article Arrays and Lists in SQL Server 2005 "describes a number of different ways to do this, both good and bad."
Duplicate of: Since there is no Sqlserver array parameter, what’s the best way to proceed?
May be I understood your question wrongly, but why not just abstract away the code that instantiates the parameter and adds it to a command object to a helper function?
Something like this...
AddSqlParam("ParamName1",SqlDbType.Int,val1,ParameterDirection.Input, command);
AddSqlParam("ParamName2",SqlDbType.String,val2,ParameterDirection.Input, command);
You can further refactor this by having commonly used parameters into little helper functions.
For example most databases have an ID column.
So you could have a method like AddIdParam(command);
I hope I conveyed my point.
This is a little bit more condensed format you could use
SqlCommand command = new SqlCommand();
command.Parameters.Add(new SqlParameter("#param1", SqlDbType.NVarChar, 255));
command.Parameters[command.Parameters.Count - 1].Value = "value1";
command.Parameters.Add(new SqlParameter("#param2", SqlDbType.NVarChar, 255));
command.Parameters[command.Parameters.Count - 1].Value = "value2";
command.Parameters.Add(new SqlParameter("#param3", SqlDbType.NVarChar, 255));
command.Parameters[command.Parameters.Count - 1].Value = "value3";