Using PetaPoco, how do i call stored procedure with typed parameters?
in c# i do it like this:
cmd.Parameters.Add("#email", SqlDbType.NVarChar).Value = email;
Check out the documentation for further details but here is an extract.
http://www.toptensoftware.com/Articles/114/PetaPoco-What-s-new-in-v4-0
Support for IDbParameters as SQL arguments
PetaPoco now supports directly passing IDbParameter objects to a
query. This is handy if PetaPoco doesn't correctly map a property.
For example the SQL Server driver doesn't handle assigning DbNull to a
VarBinary column unless the parameter is configured with the correct
type. To work around this you can now do this:
databaseQuery.Execute("insert into temp1 (t) values (#0)",
new SqlParameter() { SqlDbType = SqlDbType.VarBinary, Value = DbNull.Value });
One interesting side effect of this is that
you can also return an IDbParameter from the PetaPoco.IMapper
interface to globally override PetaPoco's default parameter mapping
functionality.
Related
I am using a SQL query and then transforming the result using Hibernates's Transformers.aliasToBean().
One of the columns in my query is an enum. The transformation somehow fails for the enum. What should I do? Which datatype should I use? I want more than 1 character to transform the result into my enum type.
This is how the simplified version of my query/code looks like (b is an enum in the table profiles):
session.createSQLQuery("select a, b from profiles").setResultTransformer(Transformers.aliasToBean(Profile.class))
.list();
Exception : expected type: Foo.ProfileStateEnum, actual value: java.lang.Character
Assuming that the java enum type that corresponds to column b is Foo.ProfileStateEnum, the following code snippet should work for you. (I tested with Hibernate 4.1.6)
import java.util.Properties;
import org.hibernate.type.Type;
import org.hibernate.type.IntegerType;
import org.hibernate.internal.TypeLocatorImpl.TypeLocatorImpl;
import org.hibernate.type.TypeResolver.TypeResolver;
import org.hibernate.type.EnumType;
Properties params = new Properties();
params.put("enumClass", "Foo.ProfileStateEnum");
params.put("type", "12"); /*type 12 instructs to use the String representation of enum value*/
/*If you are using Hibernate 5.x then try:
params.put("useNamed", true);*/
Type myEnumType = new TypeLocatorImpl(new TypeResolver()).custom(EnumType.class, params);
List<Profile> profileList= getSession().createSQLQuery("select a as ID, b from profiles")
.addScalar("ID", IntegerType.INSTANCE)
.addScalar("b", myEnumType )
.setResultTransformer(Transformers.aliasToBean(Profile.class))
.list();
I found two ways to achieve it.
Use org.hibernate.type.CustomType with org.hibernate.type.EnumType(put either EnumType.NAMED or EnumType.TYPE, see EnumType#interpretParameters). Like below:
Properties parameters = new Properties();
parameters.put(EnumType.ENUM, MyEnum.class.getName());
// boolean or string type of true/false; declare database type
parameters.put(EnumType.NAMED, true);
// string only; declare database type
parameters.put(EnumType.TYPE, String.valueOf(Types.VARCHAR));
EnumType<MyEnum> enumType = new EnumType<>();
enumType.setTypeConfiguration(new TypeConfiguration());
enumType.setParameterValues(parameters);
CustomType customEnumType = new CustomType(enumType);
Another simple way. Use org.hibernate.type.StandardBasicTypeTemplate with org.hibernate.type.descriptor.sql.*TypeDescriptor. Like below:
StandardBasicTypeTemplate<MyEnum> enumType =
new StandardBasicTypeTemplate<>(VarcharTypeDescriptor.INSTANCE,
new EnumJavaTypeDescriptor<>(MyEnum.class));
Let's see why you are getting this exception.
From the question it is obvious that you have used #Enumerated(EnumType.STRING) annotation for the field 'b' in you model class. So the field is an enum for your model class and a varchar for your database. Native SQL is not concerned about you model class and returns what ever is there in the database table as it is. So in your case, the SQLQuery you are using will return a String for 'b' instead of a ProfileStateEnum type. But your setter method for 'b' in the Profile class takes a ProfileStateEnum type argument.
Thus you get the exception "expected type: Foo.ProfileStateEnum, actual value: java.lang.Character"
You can use Aliasing to solve the problem.
What I suggest is, alias your column with any name you want and create a setter method for that alias in your model/dto.
For example, lets alias your column as 'enumStr'.
Then your query will look like this : "select a, b as enumStr from profiles"
Now, create a setter method for that alias in the your Profile class.
(Assuming that the enum ProfileStateEnum can have any of the two values STATE1 and STATE2)
public void setEnumStr(String str){
/*Convert the string to enum and set the field 'b'*/
if(str.equals(ProfileStateEnum.STATE1.toString())){
b = ProfileStateEnum.STATE1;
} else {
b = ProfileStateEnum.STATE2;
}
}
Now on transforming, the setter for the alias setEnumStr(String) will be invoked instead of setter for the field setB(ProfileStateEnum) and the string will be converted and saved to the type you want without any exceptions.
I am a beginner in Hibernate and the solution worked for me. I am using PostgreSQL. But I believe it works for other databases too.
How would you solve this? I want to return this collection:
Public Function GetShippingMethodsByCarrier(ByVal Carrier As ShippingCarrier) As List(of ?)
Return Carrier.ShippingMethods.Select(Function(x) New With {.ID = x.ID, .Name = String.Format("{0} {1}", Carrier.Name, x.Description)})
End Function
Thanks!!
You can't return an anonymous type from a function like this because it has no name.
Since this is a public function is should have a well defined return type. Create a new class holding those two properties.
Its possible to return it if the return type is an inferred generic parameter, but that's not what you want here. This is useful for LINQ where an anonymous type essentially gets passed through from a parameter to the result type, but not useful for what you're doing.
You could also use a Tuple, but then you'd lose the property names. And it wouldn't be extensible since adding a new property would break caller code. So I wouldn't recommend that either.
The problem here is you're attempting to return an anonymous type in a strongly typed manner. This is just not possible in VB.Net (or C# for that matter). Anonymous types are meant to be anonymous and their names cannot be stated explicitly in code. The two ways to work around this are to
Option #1 Use / Create a strongly named type like the following
Structure Item
Public ID as Integer
Public Name As String
Public Description As String
End Structure
Option #2 Set the return type to be Object and access the list in a late bound manner
EDIT
As CodeInChaos it is possible to return them in a strongly type manner in a generic context. But that doesn't appear to help you for this particular problem.
I can successfully connect to the database with my datacontext object. I am able to read and write to the database successfully, however I can't use the same syntax that others appear to be using.
For example, when I want data from a table, I have to do something like this:
db = new UserDataDataContext(WebConfigurationManager.ConnectionStrings["UserData"].ConnectionString);
IQueryable Users = db.GetTable<User>();
I'd like to be able to write linq queries like how I see others doing them:
db = new UserDataDataContext(WebConfigurationManager.ConnectionStrings["UserData"].ConnectionString);
var query = from u in db.User
where u.UserName == "Test"
select u;
But intellisense does not recognize User as an property of db, and thus won't compile. Intellisense doesn't show any properties that look related to tables or entities of my database.
Here is the error message I am getting:
'System.Data.Linq.DataContext' does not contain a definition for 'User' and no extension method 'User' accepting a first argument of type 'System.Data.Linq.DataContext' could be found (are you missing a using directive or an assembly reference?)
Here is a rundown of what I am doing:
I used the database designer, dragged the tables in that I wanted.
Then I saved it as a dbml file.
It then created the new class that extends dataContext for me, named UserDataDataContext. I then instantiate a new instance of UserDataDataContext named db, passing in my connection string from Web.config.
Then I try to write a linq query referencing table names as properties of the db object, but it does not recognize them.
I can't seem to find what I am doing wrong compared to all of the examples I've read. Any ideas?
I'm sure you have the following variable declaration somewhere:
// variable is of type System.Data.Linq.DataContext
DataContext db;
Change it to:
// variable is now of the appropriate subclass's type
UserDataDataContext db;
If db is a local variable and you can afford to inline the initialization and declaration together, it would be even better to use implicit typing instead:
// db is implicitly of type UserDataDataContext
var db = new UserDataDataContext(WebConfigurationManager.ConnectionStrings["UserData"].ConnectionString);
C# is a safe and statically typed language. Although the object referred to by your reference will indeed, at run-time, have the properties you are expecting, the compiler won't let this compile because these properties don't exist on the variable's type.
I want to be able to specify the properties to get populated/updated in the linq expression.
Something in the following fashion:
Proxy.UpdateEmployee(List<string> propertiesNames)
Proxy.GetEmployee() //inside the method populate only certain properties
The return values must be of known type(no anonymous types accepted).
DLINQ enable to select by specifying properties' names but the result is IQueryable interface and I'm unable to AsEnumerable() it in order to build the known type query afterwards.
You have to use reflection to modify instance properties by name.
So wherever you're updating your object with LINQ you need to do something like this:
foreach (string propName in propertiesNames)
{
PropertyInfo prop = this.GetType().GetProperty(propName);
prop.SetValue(valueForProp);
}
I am having a problem determining how c# and LINQ solve the common problem of handling a data structure that does not necessarily return a table structure, but instead a resultset.
I have a stored procedure that works, and have included it in my DBML
[Function(Name="dbo.p_GetObject")]
public int p_GetObject([Parameter(Name="ObjectType", DbType="NVarChar(200)")] string objectType, [Parameter(Name="ItemState", DbType="Bit")] System.Nullable<bool> itemState, [Parameter(Name="IsPublished", DbType="Bit")] System.Nullable<bool> isPublished)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), objectType, itemState, isPublished);
return ((int)(result.ReturnValue));
}
The dbml says that the return type is (None) and this could be the crux issue. However I don't have a DBML object that matches the resultset.
The SP takes three parameters, and returns a result set with three columns (ID, Name, Value) with multple rows. I can create a data object for this, and call it resultSet
When I write a function call for this, I get stuck:
public List<resultset> GetObject(string objectType, bool itemState, bool isPublished)
{
MyDataContext.p_GetObject(objectType, itemState, isPublished);
}
My questions are:
how do I have the data context call to the stored procedure populate my resultSet object? Is there a better approach? What should the return type be? A SQL view? Looking for good suggestions...
If it simply isn't understanding your SP, that could be the SET FMT_ONLY issue... try generating the data from a simplified version of the SP?
Normally, SPs / UDFs that don't map 1:1 with an existing entity would expose themselves in a generated type. You can rename this in the DBML file (not in the designer), but personally I wouldn't; I tend to mark the SP as private, and write my own method that projects into my own POCO type (defined for the repository):
var typed = from row in cxt.SomeFunction(123)
select new MyType {Id = row.Id, Name = row.Name, ...}
The reason for this is partly for repository purity, and partly to guard against the designer's habit of re-writing the DBML in unexpected ways ;-p See here for more.