Entity Framework 4 -- possible to call a SSDL function from within another SSDL function's commandtext? - entity-framework

Is it possible to call a SSDL function from within another SSDL function's CommandText? For example, let's say I have the following SSDL function defined in my edmx file:
<Function Name="blah" IsComposable="false">
<CommandText>
...blah related stuff...
</CommandText>
<Parameter Name="blah_param" Type="int" />
</Function>
Can I define a second SSDL function that calls "blah"? For example:
<Function Name="blah2" IsComposable="false">
<CommandText>
...
blah(3);
...
</CommandText>
<Parameter Name="blah2_param" Type="int" />
</Function>
"blah" and "blah2" do NOT exist as stored procedures on the database and are fully defined in the SSDL of the edmx. I tried qualifying the call with a handful of different things (appending the SSDL namespace to the function name -- BlahModel.Store.blah(3), using "execute procedure" and "call" SQL keywords, etc).
It appears that once it hits the CommandText tag, everything is sent over to the database and no parsing/resolving of the inner CommandText is done. Does anyone have any insight into whether this is possible or not?
Thanks!

It is not possible. CommandText should contain a valid SQL/Transact-SQL/PL/SQL expression only.

Related

Mybatis Generator's bug: configuration items should be ordered?

If I put "<commentGenerator>" after "<jdbcConnection>", MBG proposed an error that context content should match: blablabla...
But when I put "<commentGenerator>" before "<jdbcConnection>", everything is ok. Here I have something to complain to the official website that if the order of these items is need, why you do not tell us! What an important thing! You r kidding the freshmen. Maybe it is some where I do not know, but this is a key point to build the MBG's configuration file successfully, why not put this NOTE on the top of the tutorial or somewhere eye-catching?
<generatorConfiguration >
<classPathEntry location="D:\mariadb-java-client-1.1.7.jar" />
<context id="db" >
<commentGenerator>
<property name="suppressAllComments" value="true" />
<property name="suppressDate" value="true" />
</commentGenerator>
<jdbcConnection driverClass="org.mariadb.jdbc.Driver"
connectionURL="jdbc:mariadb://localhost:3306/dbname"
userId="root"
password="password"
/>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- Model Class -->
<javaModelGenerator targetPackage="org.infrastructure.model" targetProject="infrastructure\src\main\java">
<property name="enableSubPackages" value="false" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- XML Files -->
<sqlMapGenerator targetPackage="sqlMap" targetProject="infrastructure\src\main\config">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- DAO -->
<javaClientGenerator type="XMLMAPPER" targetPackage="org.infrastructure.dao" targetProject="infrastructure\src\main\java">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- Tables -->
<table tableName="user" domainObjectName="User" ></table>
</context>
</generatorConfiguration>
First of all, in your xml configuration file, it doesn't contains a valid root element, which always should be like <!DOCTYPE .../>. About how to add a correct root element of mybatis generator configuration file, please see example from MyBatis GeneratorXML Configuration File Reference.
If you correctly specified root element such as following:
<!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"
>
This root element contains a typical DTD declaration located at http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd. This is the definition of the order of these items is need. And we are going to see what it looks like.
From line 47 of this document type definition, it defines element named context. The content is as following:
<!--
The context element is used to describe a context for generating files, and the source tables.
-->
<!ELEMENT context (property*, plugin*, commentGenerator?, jdbcConnection, javaTypeResolver?,javaModelGenerator, sqlMapGenerator?, javaClientGenerator?, table+)>
Which obviously defined the order of the element in context, that is:
property*, plugin*, commentGenerator?, jdbcConnection,
javaTypeResolver?,javaModelGenerator, sqlMapGenerator?,
javaClientGenerator?, table+
In this element, all children must occurs as following rules:
+ for specifying that there must be one or more occurrences of the item — the effective content of each occurrence may be different;
* for specifying that any number (zero or more) of occurrences is allowed — the item is optional and the effective content of each occurrence may be different;
? for specifying that there must not be more than one occurrence — the item is optional;
If there is no quantifier, the specified item must occur exactly one time at the specified position in the content of the element.
After we understanding its real meaning, why you could not change the order of commentGenerator and jdbcConnection should be clear.
Maybe you want to know how to make the element out of order, question How to define DTD without strict element order could be useful.
Wish it helpful.

EF 6 query contains unmapped columns, breaking the query

I have an EDMX (Entity Framework 6.1.3) that I'm using to query two different databases. There are some minor differences between the databases but I only want the common columns. I generated the EDMX from Database A, and removed the columns that were not in Database B from the Diagram and regenerated the code.
If I query database B the query contains the columns I removed, although the final SELECT does not. This means that the query fails.
The table mapping shows the columns, but with nothing on the Value/Property side:
The exception is:
System.Data.Entity.Core.EntityCommandExecutionException : An error occurred while executing the command definition. See the inner exception for details.
----> System.Data.SqlClient.SqlException : Invalid column name 'ValidFromDate'.
Invalid column name 'ValidToDate'.
Invalid column name 'LastPulled'.
Invalid column name 'IsCurrent'.
The query that is being sent to the server is:
SELECT TOP (1)
[c].[FirstName] AS [FirstName],
[c].[LastName] AS [LastName],
[c].[HomePhone] AS [HomePhone],
[c].[WorkPhone] AS [WorkPhone],
[c].[MobilePhone] AS [MobilePhone],
[c].[Email] AS [Email],
[c].[Fax] AS [Fax]
FROM (SELECT
[Person].[FirstName] AS [FirstName],
[Person].[LastName] AS [LastName],
[Person].[HomePhone] AS [HomePhone],
[Person].[WorkPhone] AS [WorkPhone],
[Person].[MobilePhone] AS [MobilePhone],
[Person].[Email] AS [Email],
[Person].[Fax] AS [Fax],
[Person].[ValidFromDate] AS [ValidFromDate],
[Person].[ValidToDate] AS [ValidToDate],
[Person].[LastPulled] AS [LastPulled],
[Person].[IsCurrent] AS [IsCurrent]
FROM [dbo].[Person] AS [Person]) AS [c]
As you can see there is an inner-query which contains the additional columns.
At this point I'm kind of stumped as to why this is happening. How do I remove these columns from both sides of the mapping, or otherwise stop EF from putting unwanted columns in ANY part of the query?
When you use the EDMX designer and simply delete a column from an entity - this does not fully remove the column from the EDMX. Assuming you truly want it gone, you can open the EDMX file with a text editor and remove it by hand. To make sure that your manual changes trigger a rebuild of your auto-generated classes, edit it in Visual Studio and you shouldn't have an issue.
Right-click the EDMX in solution explorer
Open With...
XML (Text) Editor
I would expect if you were to open the EDMX, you would find something that looks like:
<EntityType Name="Person">
<Property Name="FirstName" Type="varchar" />
<Property Name="LastName" Type="varchar" />
<Property Name="HomePhone" Type="varchar" />
<Property Name="WorkPhone" Type="varchar" />
<Property Name="MobilePhone" Type="varchar" />
<Property Name="Email" Type="varchar" />
<Property Name="Fax" Type="varchar" />
<Property Name="ValidFromDate" Type="datetime" />
<Property Name="ValidToDate" Type="datetime" />
<Property Name="LastPulled" Type="datetime" />
<Property Name="IsCurrent" Type="short" />
</EntityType>
And you would just remove the bottom 4 columns, save and close, and rebuild the project.
EDIT: In case anyone in the future references this answer, if you do not first delete the column in the designer (like the OP did in this case), there will be two other instances of the column(s) in the XML that you would also need to remove in order for it to compile.
Thanks to #Borophyll for pointing me in roughly the right direction. Although their answer was not the solution to my issue, it did allow me to see the actual issue.
in the EDMX file there is also a entry that looks like this:
<EntitySet Name="Person" EntityType="Self.Person" store:Type="Tables" store:Schema="dbo">
<DefiningQuery>SELECT
[Person].[FirstName] AS [FirstName],
[Person].[LastName] AS [LastName],
[Person].[HomePhone] AS [HomePhone],
[Person].[WorkPhone] AS [WorkPhone],
[Person].[MobilePhone] AS [MobilePhone],
[Person].[Email] AS [Email],
[Person].[Fax] AS [Fax],
[Person].[ValidFromDate] AS [ValidFromDate],
[Person].[ValidToDate] AS [ValidToDate],
[Person].[LastPulled] AS [LastPulled],
[Person].[IsCurrent] AS [IsCurrent]
FROM [dbo].[Person] AS [Person]</DefiningQuery>
</EntitySet>
And that's where the weird sub-query was coming. I think the reason is that the table has no primary key as it is part of a staging database.
I just deleted from the SELECT statement the last four columns and everything worked.

codefluent custom stored procedure

I have a custom stored procedure with in parameters that return fields of different tables how I can map this custom stored to an entity? I only want to use like a read only values for a report I don't want to save or something like that I try to add the extra fields to the most similar entity but when I execute the method in code the extra fields are null
Solution 1: Using a view
A view allows to aggregate data from different entities.
<Article>
<Id />
<Name />
<Lines typeName="LineCollection" />
<cf:method name="LoadArticlesByCommand" body="load(string commandName) from ArticleByCommand where CommandName = #commandName" />
<cf:view name="ArticleByCommand" autoLightweight="true">
<ArticleName expression="Name"/>
<ArticleQty expression="Lines.Quantity" />
<CommandName expression="Lines.Command.Name" />
</cf:view>
</Article>
<Command>
<Id />
<Name />
<Lines typeName="LineCollection" />
</Command>
<Line setType="List">
<Article typeName="Article" key="true" />
<Command typeName="Command" key="true" />
<Quantity typeName="int" />
</Line>
http://blog.codefluententities.com/2014/04/22/views-auto-lightweight-and-the-modeler/
https://www.softfluent.com/documentation/Views_PersistentViews.html
Solution 2: Using a lightweight entity
Instead of creating a view, you can can create a lightweight entity that contains only the properties used by the stored procedure.
<cf:entity name="Person" lightweight="true">
<cf:property name="FirstName" typeName="string" />
<cf:property name="lastName" typeName="string" />
<cf:method name="ComputeBalance"
body="load () raw"
rawBody="SELECT 'John' AS FirstName, 'Doe' AS LastName" />
</cf:entity>
Solution 3: Custom mapping
For more specific values or types, a custom method can be provided to map the database values to .NET types. This custom method will be called with a DataReader as parameter, meaning that a developer could do whatever he wants.
<cf:entity name="Sample">
<cf:method name="LoadPair" body="raw" rawBody="SELECT 1234,5678"
returnTypeName="CodeFluent.Runtime.Utilities.Pair<System.Int32,System.Int32>"
cfom:methodName="On{0}" />
<cf:snippet>
private static CodeFluent.Runtime.Utilities.Pair<int,int> OnLoadPair(System.Data.IDataReader reader)
{
return new Pair<int, int>(reader.GetInt32(0), reader.GetInt32(1));
}
</cf:snippet>
</cf:entity>
You can also use OnAfterReadRecord or OnBeforeReadRecord rules
If it is not essential that you map the results of the custom stored procedure to an entity than another option is to use the built in support for DataSets.
http://blog.codefluententities.com/2011/06/22/dataset-support-in-codefluent-entities/
<cf:method name="LoadAllCities" body="raw" returnTypeName="System.Data.DataSet">
SELECT $Address::City$ FROM $Address$
</cf:method>
.
DataSet ds = Address.LoadAllCities();
foreach (DataTable table in ds.Tables)
{
foreach (DataRow row in table.Rows)
{
Console.WriteLine("City: " + row[0]);
}
}
Upon re-reading you're question I am providing another answer.
In response to the part where you said "I try to add the extra fields to the most similar entity but when I execute the method in code the extra fields are null". The following steps should be able to solve that problem.
Execute one of the automatically created stored procedure in SQL Management Studio.
Execute the stored procedure you manually created.
Verify that the fieldnames returned by both stored procedures match.
I think the above will solve your immediate problem but I still don't like the solution. The reason is that you said you picked the most similar entity. I think that is going to cause problems in the future especially if the stored procedure is not being mapped to all of the entities properties.
I would recommend either lightweight entity, view or DataSet.

Decimal output parameter rounded to integer in EF5.0

We are using existing database stored procedure similar to the one below that returns decimal output,
CREATE PROCEDURE spTest(#a int, #b decimal(18,2) output)
as
BEGIN
SELECT #b=23.22
SELECT * FROM <TABLE> where id = #a
END
When I call the stored procedure in in C# app (code below) I get the result for the output parameter as 23 instead of 23.22
ObjectParameter b = new ObjectParameter("b", typeof(System.Decimal))
var result = myentities.context.spTest(1234, b)
This exactly the same issue posted by Imre Horvath (http://social.msdn.microsoft.com/Forums/en-US/14bdde82-c084-44dd-ad83-c1305cb966d2/decimal-output-parameter-rounded-to-integer) but the difference is we are using SQL Server 2008 and entity framework 5.0. After reading the suggestion from his post I have opened the edmx file in xml editor and noticed the following for the output parameter #b as below,
<Parameter Name="b" Type="decimal" Mode="InOut"/>;
I changed it to
<Parameter Name="b" Type="decimal" Mode="InOut" Precision="18" Scale="2"/>;
and run the application and I got the result as expected (23.22)
This is a work around but not a solution as you know that changes will be lost when we update the stored procedure in the entity framework designer. In our database we have lots of stored procedure that has decimal(18,2) as output parameter. I'm wondering whether this still an issue in entity framework 5.0.
Your help will be much appreciated.
Kumar
I got the same issue with you and I have resolved it after I referenced from this article http://tiku.io/questions/1120572/decimal-output-parameter-rounded-to-integer-in-ef5-0
There is 3 steps to resolve this issue:
Right click on edmx file => Open with... => XML (text) Editor.
search text <Parameter Name="b" Type="numeric" Mode="InOut" /> then replace it by <Parameter Name="b" Type="numeric" Mode="InOut" Precision="20" Scale="2" />
search text <Parameter Name="b" Mode="InOut" Type="Decimal" /> then replace it by <Parameter Name="b" Mode="InOut" Type="Decimal" Precision="20" Scale="2" />
Hope this will help you!
In EF6, I got the same problem !
But find a simple solution.
I try to set the output ObjectParameter value,
then return the decimal with scale, like 5602.86
public decimal GetQuotationAmount(string rec_id, decimal price)
{
ObjectParameter qTA_AMT = new ObjectParameter("QTA_AMT", typeof(decimal));
qTA_AMT.Value = 100000.00m;
db.GRP_Calc_QuotationAmount(rec_id, price,qTA_AMT);
return Convert.ToDecimal(qTA_AMT.Value);
}
No, this is not fixed in EF 5.0 It probably won't be fixed in 6.0 either.
UPDATE:
I have recently updated to EF 6.0, and no, the problem is still not fixed. I guess that EF 6.0 is now Open Source so you could always patch it yourself if you are into that kind of thing.

Entity Framework designer custom property does not appear in DDL generation

I have added a custom property to the Properties dialog of the Entity Framework 5 designer through
http://msdn.microsoft.com/en-us/library/microsoft.data.entity.design.extensibility.ientitydesignerextendedproperty(v=vs.103).aspx
This works well, the property appears in the Properties dialog and it is saved in the EDMX file.
Now I'd like to use that property in the DDL generation process. I have edited the T4 template file SSDLToSQL10.tt (found at C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen).
However, the custom property doesn't seem to appear anywhere in the metadata tree. The website (in German)
http://www.databinding.net/en/blog/post/2010/12/13/entity-framework-4-erweiterte-eigenschaften-in-einer-t4-vorlage-verwenden.html
tells me that the extended property should appear in the EntityType.MetadataProperties collection, but this collection contains only the following members:
KeyMembers Members Name NamespaceName Abstract BaseType DataSpace MetadataProperties
None of those is my custom property.
Am I missing something? How can I access the IEntityDesignerExtendedProperty's value in the T4 code generation template?
EDIT: Here is the EDMX part with the custom property:
<edmx:ConceptualModels>
<Schema ...>
....
<EntityType Name="Entity1">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Type="Guid" Name="Id" Nullable="false" annotation:StoreGeneratedPattern="None" />
<Property Type="String" Name="Name" Nullable="false" />
<a:MyNewProperty xmlns:a="http://schemas.tempuri.com/MyNewProperty">True</a:MyNewProperty>
</EntityType>
I guess I have to map that custom property from CSDL to SSDL somehow.
You added the property to the CSDL (conceptual layer) while the DDL is created using the SSDL (store layer). You should be able to access the conceptual model in the SSDLToSQL10.tt but I don't think it is really what you are after. In general your property is not something the EF runtime can really use - I believe it will be just treated as an extension and ignored. If you want to add a property that is supposed to be used by the EF runtime the property must be declared in the CSDL (conceptual layer) and SSDL (store layer) and mapped correctly in the MSL (mapping layer) - with the latter being probably the most difficult.
Unless I am missing what you are trying to achieve you are probably using a wrong extension point. The IEntityDesignerExtendedProperty allows defining custom properties that shows in the property and the model browser windows in the designer but are ignored at runtime. For me it looks like you would like to add a property automatically to your model. For that I would try using the IModelTransformationExtension where you should be given the entire edmx which you will be able to modify at will (i.e. CSDL, SSDL, MSL and add elements (properties) in correct EF xml namespaces). I would try using OnBeforeModelSaved since I believe the model will be saved automatically before trying to generate the database.
I was able to achieve what I want using the edmx:CopyToSSDL=true attribute:
<edmx:ConceptualModels>
<Schema ...>
....
<EntityType Name="Entity1">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Type="Guid" Name="Id" Nullable="false" annotation:StoreGeneratedPattern="None" />
<Property Type="String" Name="Name" Nullable="false" />
<a:MyNewProperty edmx:CopyToSSDL="true"
xmlns:a="http://schemas.tempuri.com/MyNewProperty">
True
</a:MyNewProperty>
</EntityType>
This way, the transformator that generates the SSDL from the CSDL copies the annotation over to the SSDL, so I'm able to access it in the T4 template that generates the DDL SQL file.
If someone is going to use this in Entity Framework 5, please not that there is a bug (http://entityframework.codeplex.com/workitem/702), and you can workaround by using the old EDMX XML namespace:
<a:MyNewProperty edmxv2:CopyToSSDL="true"
xmlns:a="http://schemas.tempuri.com/MyNewProperty"
xmlns:edmxv2="http://schemas.microsoft.com/ado/2008/10/edmx">
True
</a:MyNewProperty>