I have scalar function:
CREATE FUNCTION [dbo].[CheckLocation]
(
#locationId Int
)
RETURNS bit
AS
BEGIN
//code
END
I want to use it in Entity Framework context.
I have added this in the *.edmx file:
<Function Name="CheckLocation" ReturnType="bit" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" >
<Parameter Name="locationId" Type="int" Mode="In" />
</Function>
I have also created a partial class with method decorated with EdmFunctionAttribute:
public partial class MainModelContainer
{
[EdmFunction("MainModel.Store", "CheckLocation")]
public bool CheckLocation(int locationId)
{
throw new NotSupportedException("Direct calls not supported");
}
}
I try to use this function like this:
Context.CheckLocation(locationId);
And get NotSupportedException("Direct calls not supported").
It works within Select method, but it does not suit me.
Help please!
How can I call this function without select method?
you need to access it as a select
var students = context.Locations
.Select ( new { location= CheckLocation(locationId)}):
Related
Hey I have create my own service.xml with student. Now o want to add my own searchByName method for student. can you please explain me what to write in StudentLocalServiceImpl.
public class StudentLocalServiceImpl extends StudentLocalServiceBaseImpl {
/*
* NOTE FOR DEVELOPERS:
*
*/
public List<Student> getAll() throws SystemException {
return studentPersistence.findAll();
}
public Student getStudentByName(String name) {
return studentPersistence.
}
// I have created one method getAll. I need help for the another one.
Thanks in Advance.
You would first declare this as a "finder" element in the service.xml within the entity you defined.
e.g.
<finder name="Name" return-type="Student">
<finder-column name="name" />
</finder>
The return-type could also be Collection if wanting a List<Student> as the return type, if name is not unique.
<finder name="Name" return-type="Collection">
<finder-column name="name" />
</finder>
You can also state a comparison operator for the column:
<finder name="NotName" return-type="Collection">
<finder-column name="name" comparator="!=" />
</finder>
A finder can actually declare a unique index as well to be generated on this relation (will be applied to the DB table) by specifying the unique="true" attribute on the finder:
<finder name="Name" return-type="Student" unique="true">
<finder-column name="name" />
</finder>
With this definition and after re-runing ant build-service the studentPersistence will contain new methods using the name of the finder found in the xml element appended with a prefix: countBy, findBy, fetchBy, removeBy, etc.
Finally, your serice method would only need to contain the following (based on the above):
public Student getStudentByName(String name) throws SystemException {
return studentPersistence.findByName(name);
}
HTH
I've got an Entity Framework 4 entity model in my program. There's a stored function I've defined in my SQL Anywhere 12.0.1 database called GuidToPrefix:
CREATE OR REPLACE FUNCTION GuidToPrefix( ID UNIQUEIDENTIFIER ) RETURNS INT AS
BEGIN
RETURN CAST( CAST( ID AS BINARY(4) ) AS INT )
END;
Following the directions in this MSDN article, I added the function to my EDMX:
<Function Name="GuidToPrefix" ReturnType="int" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="DBA">
<Parameter Name="ID" Type="uniqueidentifier" Mode="In" />
</Function>
To be totally honest, I updated the model from the database and checked off the function in the list on the first tab of the wizard. I don't know if that makes a difference or not, but I can't see why it would.
According to the article, I need to add a definition of the function in a C# class. My problem is it doesn't tell me what class to put that in. Do I add an entirely new class? Do I create a new .CS file and do something like this:
public static DbFunctions {
[EdmFunction( "CarSystemModel.Store", "GuidToPrefix" )]
public static int GuidToPrefix( Guid id ) {
throw new NotSupportedException( "Direct calls to GuidToPrefix are not supported." );
}
}
or do I put that in a partial of the entities class?
partial MyEntities {
[EdmFunction( "CarSystemModel.Store", "GuidToPrefix" )]
public static int GuidToPrefix( Guid id ) {
throw new NotSupportedException( "Direct calls to GuidToPrefix are not supported." );
}
}
I have two projects where this entity model is used. One is a class library and the model is definied in it. The other is another class library in another solution that just uses it. I've tried both examples above and the query in the second class library generates this error from the compiler in both cases:
The name 'GuidToPrefix' does not exist in the current context
Obviously I'm not doing something right. Has anyone tried this and got it to work?
I found the answer to this one.
Recall that I created a file with a partial of the MyEntities class in my project where the Entity Model is defined:
partial MyEntities {
[EdmFunction( "CarSystemModel.Store", "GuidToPrefix" )]
public static int GuidToPrefix( Guid id ) {
throw new NotSupportedException( "Direct calls to GuidToPrefix are not supported." );
}
}
This was fine and it all compiled. My problem wasn't here but in the project where I have to use the function.
In that project, in a class called DataInterface, I have a method with code like this:
var query = from read in context.Reads
from entry in context.Entries
.Where( e => GuidToPrefix( read.ID ) == e.PrefixID && read.ID == e.ID )
.....
The problem was that I needed to add the name of the class that contained the C# declaration of the GuidToPrefix function in the Where clause. That is, I needed to write the above expression as:
var query = from read in context.Reads
from entry in context.Entries
.Where( e => MyEntities.GuidToPrefix( read.ID ) == e.PrefixID && read.ID == e.ID )
.....
This compiles and when it runs it uses the function in the database in the LEFT OUTER JOIN as I wanted.
Are scalar udfs accessible to execute with EF?
Thanks
Yes. This is supported, here is a quick walk through on howto do it.
Alter your EF SSDL:
<Function Name="AvgStudentGrade" ReturnType="decimal" Schema="dbo" >
<Parameter Name="studentId" Mode="In" Type="int" />
</Function>
Add a method stub with the appropriate attributes:
[EdmFunction("SchoolModel.Store", "AvgStudentGrade")]
public static decimal? AvgStudentGrade(int studentId)
{
throw new NotSupportedException("Direct calls are not supported.");
}
Use it:
var students = from s in context.People
where s.EnrollmentDate != null
select new
{
name = s.LastName,
avgGrade = AvgStudentGrade(s.PersonID)
};
More info and full sample at:
http://msdn.microsoft.com/en-us/library/dd456847(VS.100).aspx
Suppose you have a table with the name MyDbSet, it can be any table you want. Then create a record with guid "test", then use the approach below to execute a ef scalar function and return the result.
MyDbSet
.Where(o => o.Guid == "test")
.Select(o => EF.Functions.ToTsVector(request.Keywords))
.FirstOrDefault();
I am trying to do the following:
http://msdn.microsoft.com/en-us/library/dd456857.aspx
I created the function in the edmx file here just before the schema element:
<Function Name="YearsSince" ReturnType="Edm.Int32">
<Parameter Name="date" Type="Edm.DateTime" />
<DefiningExpression>
Year(CurrentDateTime()) - Year(AppliedDate)
</DefiningExpression>
</Function>
</Schema>
Now, I want to be able to use that in a query.
I created the following code in the ApplicantPosition partial class
[EdmFunction("HRModel", "YearsSince")]
public static int YearsSince(DateTime date)
{
throw new NotSupportedException("Direct calls are not supported.");
}
And I am trying to do the following query
public class Class1
{
public void question()
{
using (HREntities context = new HREntities())
{
// Retrieve instructors hired more than 10 years ago.
var applicantPositions = from p in context.ApplicantPositions
where YearsSince((DateTime)p.AppliedDate) > 10
select p;
foreach (var applicantPosition in applicantPositions)
{
Console.WriteLine(applicantPosition.);
}
}
}
}
The YearsSince is not recognized, the MSDN tutorial does not show exactly where I need to put the functio, so that might be my problem.
Your static YearsSince function must be defined in some class so if it is not Class1 you must use full identification with class name to call it. Check also this answer.
Currently working on upgrading from iBatis to myBatis. In ibatis we would have a sql map like so
<resultMap id="PCRV_HIERARCHY_LVL_LIST_MAP" class="com.fmrco.sai.aadpm.domain.ConstraintHierarchyLevel">
<result property="levelId" column="LEVEL_ID"/>
<result property="levelDescription" column="LEVEL_DESCRIPTION"/>
<result property="levelRank" column="LEVEL_RANK"/>
<result property="levelCode" column="LEVEL_CODE"/>
</resultMap>
<parameterMap id="GET_HIERARCHY_LVL_LIST_MAP" class="java.util.Map">
<parameter property="PCRV_HIERARCHY_LVL_LIST" jdbcType="ORACLECURSOR" javaType="java.sql.ResultSet" mode="OUT" resultMap="PCRV_HIERARCHY_LVL_LIST_MAP"/>
</parameterMap>
<procedure id="GET_HIERARCHY_LVL_LIST" parameterMap="GET_HIERARCHY_LVL_LIST_MAP">
{ call GET_HIERARCHY_LVL_LIST ( ? ) }
</procedure>
I'd like to fully utilize the functionality provided by myBatis (such as not needing to implement an implementation of a mapper and avoiding using deprecated features such as parameterMap) but I'm having some issues. I kept running into errors trying to set the return properties so I had to wrap my resultSet object in a wrapper object which is something I'd like to avoid
Mapper.java
public void getHierarchyLevels(ListConstraintHierarchyLevel constraintHierarchyLevels);
ConstraintHierarchyLevel class
public class ListConstraintHierarchyLevel {
private List<ConstraintHierarchyLevel> constraintHierarchyLevels ;
public List<ConstraintHierarchyLevel> getConstraintHierarchyLevels() {
return constraintHierarchyLevels;
}
public void setConstraintHierarchyLevels(List<ConstraintHierarchyLevel> constraintHierarchyLevels) {
this.constraintHierarchyLevels = constraintHierarchyLevels;
}
}
mapper.xml
<resultMap id="HierarchyLvlMap" type="com.fmrco.sai.aadpm.domain.ConstraintHierarchyLevel">
<result property="levelId" column="LEVEL_ID"/>
<result property="levelDescription" column="LEVEL_DESCRIPTION"/>
<result property="levelRank" column="LEVEL_RANK"/>
<result property="levelCode" column="LEVEL_CODE"/>
</resultMap>
<select statementType="CALLABLE"
id="getHierarchyLevels"
parameterType="com.fmrco.sai.aadpm.domain.ListConstraintHierarchyLevel"
resultMap="HierarchyLvlMap">
{ call GET_HIERARCHY_LVL_LIST (
#{constraintHierarchyLevels,
jdbcType=CURSOR,
mode=OUT,
javaType=java.sql.ResultSet,
resultMap=HierarchyLvlMap}
) }
</select>
I have attempted another solution unsuccessfully. In this solution I make use of the param annotation
mapper.java
public void getHierarchyLevelsWithParam(#Param("constraintHierarchyLevels") List<ConstraintHierarchyLevel> constraintHierarchyLevels);
I use the same resultMap as above but with a different select block
mapper.xml
<select statementType="CALLABLE"
id="getHierarchyLevelsWithParam"
parameterType="list"
resultMap="HierarchyLvlMap">
{ call GET_HIERARCHY_LVL_LIST (
#{constraintHierarchyLevels,
jdbcType=CURSOR,
mode=OUT,
javaType=java.sql.ResultSet,
resultMap=HierarchyLvlMap}
) }
When running this I have debugged into the MapperMethod class to the execute method and the Object param gets the correct data from the result set however as this does not get placed into the argument sent down (List) these values do not get returned. When running the first method with the object wrapper the objects are placed in the argument sent down and thus are retrievable.
Thanks
I don't know any other way than wrapping result object.
Indeed, the OUT variable has to be bound on something, this is a variable scope issue, then indirection is mandatory. But it can be generic:
class Wrapper<T> {
private List<T> member;
}
The #Param annotation is actually used to give parameters a name to uses as reference in the SQL (especially if the mapper method has multiple parameters)