I'm mapping an Oracle 11g stored procedure as command in a NHibernate's .hbm.xml mapping file, like this:
<class name="Person" table="PERSONS">
<id name="Id" column="COD_PERSON" />
<property name="Name" column="NAME" />
<property name="AuditField1" column="AUDITFIELD1" />
<property name="AuditField2" column="AUDITFIELD2" />
<property name="AuditField3" column="AUDITFIELD3" />
<sql-insert>exec PKG_PERSONS.insert_sp ?,?</sql-insert>
</class>
This is the stored procedure:
create or replace package body PKG_PERSONS is
procedure insert_sp(pcod_person persons.cod_person%type,
pname persons.name%type) is
begin
insert into persons(cod_person, name) values(pcod_person, pname);
end;
From this mapping, I'm expecting 'Id' and 'Name' properties would be send as parameters, but for sure, this isn't happening; I'm getting this error from Oracle: ORA-01036: illegal variable name/number. NHibernate shows some logs in Console window and it seems like NH tries to map all properties, included AuditFields, to invoke the stored procedure.
Maybe is this the source's error?
Is this the expected behaviour?
Is it possible to specific what properties send as parameter with NH3/Oracle?
Thanks in advance.
Confirmed, NH tries to send as parameter every entity's properties mapped to <sql-insert>/<sql-update> stored procedures, but you could make exceptions with insert/update=false.
Another issue was the right sintaxis to execute Oracle11g's stored procedure, this is the mapping that works for me with NH3.3 and Oracle.DataAccess 4.112.2.0:
<class name="Person" table="PERSONS">
<id name="Id" column="COD_PERSON" />
<property name="Name" column="NAME" />
<property name="AuditField1" column="AUDITFIELD1" insert="false" update="false" />
<property name="AuditField2" column="AUDITFIELD2" insert="false" update="false" />
<property name="AuditField3" column="AUDITFIELD3" insert="false" update="false" />
<sql-insert check="none">begin PKG_PERSONS.insert_sp(:p0,:p1); end;</sql-insert>
</class>
I had to redefine the parameter's order, because Id property is send at last position:
create or replace package body PKG_PERSONS is
procedure insert_sp(pname persons.name%type,
pcod_person persons.cod_person%type
) is
begin
insert into persons(cod_person, name) values(pcod_person, pname);
end;
Maybe this will help somebody else,
Thanks.
Related
I want to receive CLOB data of CONTENT column as java.lang.String value with only sql mapper definition.
Select query is something like this.
<select id="selectById">
<![CDATA[
SELECT
ID -- // NUMBER
, TITLE -- // VARCHAR2(2000)
, CONTENT -- // CLOB
FROM FAQ
WHERE ID = #{id}
]]>
</select>
Is it possible? I've googled over an hour and realized <resultMap /> can be the solution.
But, I can't figure out any more. Please help me.
I'll show you two approaches.
The first solution is to use <resultMap />.
You just need to specify javaType for the CONTENT column.
<resultMap type="map" id="faqRM">
<id property="ID" column="ID" />
<result property="TITLE" column="TITLE" />
<result property="CONTENT" column="CONTENT" javaType="string" />
</resultMap>
and specify resultMap in the <select />.
<select id="selectById" resultMap="faqRM">
The second approach is to specify the type handler for CLOB vs Object conversion globally in the config.
<typeHandlers>
<typeHandler javaType="java.lang.Object" jdbcType="CLOB"
handler="org.apache.ibatis.type.StringTypeHandler" />
</typeHandlers>
Then you can simply specify resultType="map" instead of defining <resultMap />.
<select id="selectById" resultType="map">
I should also mention that java.lang.String has smaller capacity than CLOB (2GB - 1 vs 4GB - 1 last time I checked).
Is there a simple way of taking the value of a property and then copy it to another property with certain characters replaced?
Say propA=This is a value. I want to replace all the spaces in it into underscores, resulting in propB=This_is_a_value.
Here is the solution without scripting and no external jars like ant-conrib:
The trick is to use ANT's resources:
There is one resource type called "propertyresource" which is like a source file, but provides an stream from the string value of this resource. So you can load it and use it in any task like "copy" that accepts files
There is also the task "loadresource" that can load any resource to a property (e.g., a file), but this one could also load our propertyresource. This task allows for filtering the input by applying some token transformations. Finally the following will do what you want:
<loadresource property="propB">
<propertyresource name="propA"/>
<filterchain>
<tokenfilter>
<filetokenizer/>
<replacestring from=" " to="_"/>
</tokenfilter>
</filterchain>
</loadresource>
This one will replace all " " in propA by "_" and place the result in propB. "filetokenizer" treats the whole input stream (our property) as one token and appies the string replacement on it.
You can do other fancy transformations using other tokenfilters: http://ant.apache.org/manual/Types/filterchain.html
Use the propertyregex task from Ant Contrib.
I think you want:
<propertyregex property="propB"
input="${propA}"
regexp=" "
replace="_"
global="true" />
Unfortunately the examples given aren't terribly clear, but it's worth trying that. You should also check what happens if there aren't any underscores - you may need to use the defaultValue option as well.
If ant-contrib isn't an option, here's a portable solution for Java 1.6 and later:
<property name="before" value="This is a value"/>
<script language="javascript">
var before = project.getProperty("before");
project.setProperty("after", before.replaceAll(" ", "_"));
</script>
<echo>after=${after}</echo>
In case you want a solution that does use Ant built-ins only, consider this:
<target name="replace-spaces">
<property name="propA" value="This is a value" />
<echo message="${propA}" file="some.tmp.file" />
<loadfile property="propB" srcFile="some.tmp.file">
<filterchain>
<tokenfilter>
<replaceregex pattern=" " replace="_" flags="g"/>
</tokenfilter>
</filterchain>
</loadfile>
<echo message="$${propB} = "${propB}"" />
</target>
Output is ${propB} = "This_is_a_value"
Use some external app like sed:
<exec executable="sed" inputstring="${wersja}" outputproperty="wersjaDot">
<arg value="s/_/./g"/>
</exec>
<echo>${wersjaDot}</echo>
If you run Windows get it googling for "gnuwin32 sed".
The command s/_/./g replaces every _ with .
This script goes well under windows. Under linux arg may need quoting.
Two possibilities :
via script task and builtin javascript engine (if using jdk >= 1.6)
<project>
<property name="propA" value="This is a value"/>
<script language="javascript">
project.setProperty('propB', project.getProperty('propA').
replace(" ", "_"));
</script>
<echo>$${propB} => ${propB}</echo>
</project>
or using Ant addon Flaka
<project xmlns:fl="antlib:it.haefelinger.flaka">
<property name="propA" value="This is a value"/>
<fl:let> propB := replace('${propA}', '_', ' ')</fl:let>
<echo>$${propB} => ${propB}</echo>
</project>
to overwrite exisiting property propA simply replace propB with propA
Here's a more generalized version of Uwe Schindler's answer:
You can use a macrodef to create a custom task.
<macrodef name="replaceproperty" taskname="#{taskname}">
<attribute name="src" />
<attribute name="dest" default="" />
<attribute name="replace" default="" />
<attribute name="with" default="" />
<sequential>
<loadresource property="#{dest}">
<propertyresource name="#{src}" />
<filterchain>
<tokenfilter>
<filetokenizer/>
<replacestring from="#{replace}" to="#{with}"/>
</tokenfilter>
</filterchain>
</loadresource>
</sequential>
</macrodef>
you can use this as follows:
<replaceproperty src="property1" dest="property2" replace=" " with="_"/>
this will be pretty useful if you are doing this multiple times
Adding an answer more complete example over a previous answer
<property name="propB_" value="${propA}"/>
<loadresource property="propB">
<propertyresource name="propB_" />
<filterchain>
<tokenfilter>
<replaceregex pattern="\." replace="/" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
Just an FYI for answer Replacing characters in Ant property - if you are trying to use this inside of a maven execution, you can't reference maven variables directly. You will need something like this:
...
<target>
<property name="propATemp" value="${propA}"/>
<loadresource property="propB">
<propertyresource name="propATemp" />
...
Properties can't be changed but antContrib vars (http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html ) can.
Here is a macro to do a find/replace on a var:
<macrodef name="replaceVarText">
<attribute name="varName" />
<attribute name="from" />
<attribute name="to" />
<sequential>
<local name="replacedText"/>
<local name="textToReplace"/>
<local name="fromProp"/>
<local name="toProp"/>
<property name="textToReplace" value = "${#{varName}}"/>
<property name="fromProp" value = "#{from}"/>
<property name="toProp" value = "#{to}"/>
<script language="javascript">
project.setProperty("replacedText",project.getProperty("textToReplace").split(project.getProperty("fromProp")).join(project.getProperty("toProp")));
</script>
<ac:var name="#{varName}" value = "${replacedText}"/>
</sequential>
</macrodef>
Then call the macro like:
<ac:var name="updatedText" value="${oldText}"/>
<current:replaceVarText varName="updatedText" from="." to="_" />
<echo message="Updated Text will be ${updatedText}"/>
Code above uses javascript split then join, which is faster than regex. "local" properties are passed to JavaScript so no property leakage.
Or... You can also to try Your Own Task
JAVA CODE:
class CustomString extends Task{
private String type, string, before, after, returnValue;
public void execute() {
if (getType().equals("replace")) {
replace(getString(), getBefore(), getAfter());
}
}
private void replace(String str, String a, String b){
String results = str.replace(a, b);
Project project = getProject();
project.setProperty(getReturnValue(), results);
}
..all getter and setter..
ANT SCRIPT
...
<project name="ant-test" default="build">
<target name="build" depends="compile, run"/>
<target name="clean">
<delete dir="build" />
</target>
<target name="compile" depends="clean">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes" includeantruntime="true"/>
</target>
<target name="declare" depends="compile">
<taskdef name="string" classname="CustomString" classpath="build/classes" />
</target>
<!-- Replacing characters in Ant property -->
<target name="run" depends="declare">
<property name="propA" value="This is a value"/>
<echo message="propA=${propA}" />
<string type="replace" string="${propA}" before=" " after="_" returnvalue="propB"/>
<echo message="propB=${propB}" />
</target>
CONSOLE:
run:
[echo] propA=This is a value
[echo] propB=This_is_a_value
When I make the following AppleScript call to my app, I get a list of text objects:
tell "MyApp"
name of every myobject
end tell
But the following call returns an error:
tell "MyApp"
name of selected myobjects
end tell
Script Error
MyApp got an error: Can't make name of selected MyObjects into type specifier.
I turned on verbose logging with the -NSScriptingDebugLogLevel 1 argument to my app, which gave me this:
2015-01-27 14:33:53.650 MyApp[4848:2572448] Error converting apple event to script command: -1700
2015-01-27 14:33:53.650 MyApp[4848:2572448] Original event: <NSAppleEventDescriptor: 'core'\'getd'{ '----':'obj '{ 'form':'prop', 'want':'prop', 'seld':'pnam', 'from':'obj '{ 'form':'prop', 'want':'prop', 'seld':'MASM', 'from':null() } }, &'csig':65536 }>
2015-01-27 14:33:53.650 MyApp[4848:2572448] Offending object descriptor: <NSAppleEventDescriptor: 'obj '{ 'form':'prop', 'want':'prop', 'seld':'pnam', 'from':'obj '{ 'form':'prop', 'want':'prop', 'seld':'MASM', 'from':null() } }>
2015-01-27 14:33:53.651 MyApp[4848:2572448] Expected type descriptor: <NSAppleEventDescriptor: 'obj '>
This is the "application" section of my sdef file:
<class name="application" code="capp" plural="applications" inherits="application">
<cocoa class="MyApp.MAApplication" />
<element type="myobject" access="r">
<cocoa key="myobjects" />
</element>
<property name="selected myobjects" code="MASM">
<cocoa key="selectedMyObjects" />
<type type="myobject" list="yes" />
</property>
</class>
And the MyObject class:
<class name="myobject" code="MAMO" inherits="item" plural="myobjects">
<cocoa class="MyObject" />
<property name="id" code="ID " type="text" access="r">
<cocoa key="permanentID" />
</property>
<property name="name" code="pnam" type="text" access="r">
<cocoa key="displayName" />
</property>
</class>
When I just call selected myobjects, I get back a list of identifiers, so that part is working correctly. When can't I get the name or other properties back from that list, when I can with another list specified the exact same way (except as an element instead of property)?
Update
Still not having any luck so far. I noticed, with verbose logging, that when I call name of every MyObject, the command "Intrinsics.get" triggers with an NSPropertySpecifier "displayName of myobjects". Apparently that link doesn't get made when using a property rather than an element to return a list of items. I found a workaround, though, since I specify an is selected property on MyObject. You can call:
name of every myobject whose is selected = true
That works the way I expected my selected myobjects property to work, returning a list of text objects.
Update 2
I added a sample project to GitHub:
https://github.com/abbeycode/AppleScriptObjectList
That contains a sample script with the first two methods that behave as expected, followed by the one that triggers the error. Feel free to mess around if you'd like. I submitted a radar with this sample project.
When working with CSV files and restarting a FAILED Job, a StepExecutionListner and associated beforeStep( ....) method can be used to position
the reader within the file. So the code could look something like:
public void beforeStep(StepExecution stepExecution) {
ExecutionContext executionContext = stepExecution.getExecutionContext();
if (executionContext.containsKey(getKey(LINES_READ_COUNT))) {
long lineCount = executionContext.getLong(getKey(LINES_READ_COUNT));
LineReader reader = getReader();
Object record = "";
while (reader.getPosition() < lineCount && record != null) {
record = readLine();
}
}
} // Or something similar
My question is how do you achieve the same thing when working with a StaxEventItemReader?
My batch_step_execution_context looks something like {"string":"StaxEventItemReader.read.count","int":6}. So in my case the
the first 5 XML fragment were successfully processed and upon restarting the Job I would like to start processing from XML fragment number 6 onwards.
Given the config below, how would I position the reader within the XML file?
<batch:job id="reportJob" restartable="true">
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="xmlItemReader" writer="cvsFileItemWriter" processor="filterReportProcessor"
commit-interval="1">
</batch:chunk>
<batch:listeners>
<batch:listener ref="step1Listener" />
</batch:listeners>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="step1Listener" class="com.mkyong.listeners.Step1Listener" />
<bean id="filterReportProcessor" class="com.mkyong.processor.FilterReportProcessor" />
<bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="fragmentRootElementName" value="record" />
<property name="resource" value="classpath:xml/report.xml" />
<property name="unmarshaller" ref="reportUnmarshaller" />
</bean>
<!-- Read and map values to object, via jaxb2 -->
<bean id="reportUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.mkyong.model.Report</value>
</list>
</property>
</bean>
Environment - spring-batch-core-2.2.0; spring-core-3.2.2
Test Input File
Convert a XML file into a CSV file.
<company>
<record refId="1001">
<name>mkyong</name>
<age>31</age>
<dob>31/8/1982</dob>
<income>200,000</income>
</record>
<record refId="1002">
<name>kkwong</name>
<age>30</age>
<dob>26/7/1983</dob>
<income>100,999</income>
</record>
<record refId="1003">
<name>joel</name>
<age>29</age>
<dob>21/8/1984</dob>
<income>1,000,000</income>
</record>
<record refId="1004">
<name>leeyy</name>
<age>29</age>
<dob>21/3/1984</dob>
<income>80,000.89</income>
</record>
<record refId="1005">
<name>Grant</name>
<age>29</age>
<dob>21/3/1984</dob>
<income>80,000.89</income>
</record>
</company>
Test Run 1
After processing two records in the input file, I forced a RunTimeException.
batch_job_execution --->> "FAILED";"FAILED";"java.lang.RuntimeException: Get me out of here!
batch_step_execution_context --->> {"string":"StaxEventItemReader.read.count","int":2}
Output CSV file --->> 1001,mkyong,31,31/08/1982,200000
1002,kkwong,30,26/07/1983,100999
Test Run 2
Process all "remaining data", so expecting .... refId="1003", refId="1004", refId="1005"
batch_job_execution --->> "COMPLETED";"COMPLETED";"''";"2015-01-25 16:18:08.587"
batch_step_execution_context --->> {"string":"StaxEventItemReader.read.count","int":6}
Output CSV file --->> 1001,mkyong,31,31/08/1982,200000
1002,kkwong,30,26/07/1983,100999
1003,joel,29,21/08/1984,1000000
1004,leeyy,29,21/03/1984,80000.89
1005,Grant,29,21/03/1984,80000.89
Test Result
Unfortunately it looks like the StaxEventItemReader is reading from the beginning of the file, rather than re-positioning itself based on the value of StaxEventItemReader.read.count which is set to 2 after the first test.
You don't need to configure anything, this is already the default behavior of the StaxEventItemReader. When it opens it repositions itself from the read count in the step execution context.
while making of POC of LINQ to SQL and entities, i faced a problem stuck in a frozen dead end.
Problem is , am using LINQ to SP and every things was working fine and i made cool methods of editing, adding and deleting. Then some thing click in my mine that "what if i just return two record set from SP". i made a SP and returned two record set from it
SP look like this [Demo]
Create PROCEDURE [dbo].GetUserData
#UserId Bigint
AS
BEGIN
SET NOCOUNT ON;
-- Getting User
select * from [User] where id=#UserId
-- Getting User's role
select * from [Role] where userId=#UserId
end
then i droped that SP in my DBML (Linq to SQL classes) then here i noticed that only schema of one record set was created like this
<?xml version="1.0" encoding="utf-8"?>
<Database Name="MyInventory" Class="MyDBMLDataContext" xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
<Connection Mode="AppSettings" ConnectionString="Data Source=MyDatabaseServer\;Initial Catalog=MyInventory;Integrated Security=True" SettingsObjectName="ConsoleApplication16.Properties.Settings" SettingsPropertyName="MyInventoryConnectionString" Provider="System.Data.SqlClient" />
<Function Name="dbo.GetUserData" Method="GetUserData">
<Parameter Name="UserId" Parameter="userId" Type="System.Int64" DbType="BigInt" />
<ElementType Name="GetUserDataResult">
<Column Name="Id" Type="System.Int64" DbType="BigInt NOT NULL" CanBeNull="false" />
<Column Name="Name" Type="System.String" DbType="VarChar(50) NOT NULL" CanBeNull="false" />
<Column Name="Email" Type="System.String" DbType="NVarChar(50)" CanBeNull="true" />
<Column Name="IsDeleted" Type="System.Boolean" DbType="Bit NOT NULL" CanBeNull="false" />
<Column Name="HomePage" Type="System.String" DbType="VarChar(100)" CanBeNull="true" />
</ElementType>
</Function>
</Database>
i can clearly see that only one record set is created of Users records and it is missing Role schema :(.
Can any body tell me what and why is that so?
Thanks
Lura
I have had to deal with something similar in getting multiple data sets from a data base for a website. What we did was create an DatabaseExtensions.cs file to add the queries with multiple data sets.
So in the extensions file we would have something like this
public partial class DataBaseDataContext
{
[ResultType(typeof(FirstResult))]
[ResultType(typeof(SecondResult))]
[Function(Name = "dbo.StoredProc")]
public IMultipleResults StoredProc([global::System.Data.Linq.Mapping.ParameterAttribute(DbType = "Int")] System.Nullable<System.Int> ID)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), ID);
return ((IMultipleResults)(result.ReturnValue));
}
}
public class FirstResult;
public class SecondResult;
Note: I changed some of the names of things in this code to make it easier to read, so it may not work as is.
FirstResult and SecondResult are the result type classes. I would usually copy them from the dbml's accompanying .cs file then rename it. I didn't include their code here because it can be rather long.
DataBaseDataContext dataCon = new DataBaseDataContext();
var results = dataCon.StoredProc(id);
var firstSet = results.GetResult<FirstResult>();
var secondSet = results.GetResult<SecondResult>();
//process data
It is important to get your results out in the same order they come out in your stored procedure. After you have gotten your results out, you can use LINQ or whatever to work with them.
My finding is that if you add a result set to your dbml manually you get the results that you want but LinqToSql doesn't offer you a simple way to have access to them
Here is a path to your results
((System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReaderSession
<System.Data.SqlClient.SqlDataReader>)
(((System.Data.Linq.SqlClient.SqlProvider.ExecuteResult)(result)).session)).buffer
you here have access to your result by index buffer[0] will return the results of your first select statement and buffer[1] returns the result of second select.
probably you can cast this two IEnumerables to typed IEnumerable<GetAllResult> and IEnumerable<GetAllResult1> although I didn't test that.
I build this sample dbml
<Function Name="dbo.GetAll" Method="GetAll">
<ElementType Name="GetAllResult">
<Column Name="ID" Type="System.Int32" DbType="Int" CanBeNull="true" />
<Column Name="Tagname" Type="System.String" DbType="NChar(10)" CanBeNull="true" />
</ElementType>
<ElementType Name="GetAllResult1">
<Column Name="Id" Type="System.Int32" DbType="Int" CanBeNull="true" />
<Column Name="TagId" Type="System.Int32" DbType="Int" CanBeNull="true" />
<Column Name="Name1" Type="System.String" DbType="NChar(10)" CanBeNull="true" />
</ElementType>
</Function>
and the generated cs file would be like this
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.GetAll")]
[global::System.Data.Linq.Mapping.ResultTypeAttribute(typeof(GetAllResult))]
[global::System.Data.Linq.Mapping.ResultTypeAttribute(typeof(GetAllResult1))]
public IMultipleResults GetAll()
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())));
return ((IMultipleResults)(result.ReturnValue));
}
Have you looked code generated for your model? Two resultsets will be here. Mapping can lie.
Ramesh