using edm Number Mapping - entity-framework

In my Oracle database I have a field that has a datatype as Number(3). When I add a edm model and tell it to use code first from database, the model comes back on the .net side as a byte
public byte Quantity { get; set; }
I have tried to use the edmNumberMapping tag in the web.config, but it never changes the type when the model is built. Here is the number mapping.
<edmMappings>
<edmNumberMapping>
<add NETType="bool" MinPrecision="1" MaxPrecision="1" DBType="Number" />
<add NETType="int" MinPrecision="2" MaxPrecision="5" DBType="Number" />
<add NETType="int32" MinPrecision="6" MaxPrecision="10" DBType="Number" />
<add NETType="int64" MinPrecision="11" MaxPrecision="19" DBType="Number" />
</edmNumberMapping>
</edmMappings>
I'm trying to get the Quantity field in the database to come back as an int data type. I have read other questions and it seems like a lot of people are having the same issue. Has anyone figured this out yet? Or can tell me what else I can try? VS2015, Oracle 11g, and entity framework 6.

Related

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.

Recommended way to add a new entity to sylius core bundle?

Currently using:
base install of sylius-standard, for an ecommerce website.
Here is what I would like to accomplish :
Basically we know there is an User Entity which resides in
vendor/sylius/sylius/src/Sylius/Component/Core/Model/User.php
This Entity is actually extending the FOS\UserBundle\Model\User and it also has a linked UserInterface which is implementing FOS\UserBundle\Model\UserInterface.
My goal is to create another entity UserData which can be linked via the Doctrine OneToMany field relation to the above sylius User Entity which is basically the table sylius_user.
So effectively User Entity linked to UserData Entity via oneToMany ( For each user there can be multiple UserData entity instances.)
Sylius documentation (http://sylius.readthedocs.org) does not have anything related to adding an entity - If I am mistaken, please guide me to the correct links.
I have read overriding models at - > sylius models override also have gone through another sort of related question on stackoverflow How to create a new model with Sylius via SyliusResourceBundle but it is not clear as he is using the SyliusResourceBundle while I want to extend the SyliusCoreBundle (not sure if we can extend it in the first place or not)
How do I achieve this in the sylius framework ?
I solved the problems by reading segregated posts, so putting in here the solution for the community (please let me know if this is not the recommended way and the correct way if not):
My goal was to create a oneToMany doctrine relationship between
Sylius\Component\Core\Model\User
And
Acme\Bundle\Entity\UserData
which I had created. Basically for every user there could be multiple userdata instances pointing back to that user.
To do this, at first I followed the docs at sylius documentation
to override the sylius user class which is infact an extended class of fosuserbundle.
At some stage I kept getting the error [Doctrine\DBAL\Schema\SchemaException]
The table with name 'astrohealing_dev.sylius_user' already exists.
Based on Winzou's suggestion : To fix this error I changed the user class locations in sylius.yml (Sylius/Bundle/CoreBundle/Resources/config/app/sylius.yml) which is part of the core bundle and declared my own class as the user model like this :
This resolved the sylius_user table exists error
But then I got another error :
[Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException]
Configuration path "sylius_core.driver" cannot be overwritten. You have to define all options for this path, and any of its sub
-paths in one configuration section.
Next I commented out drive : doctrine/orm line for the relevant entry in
app/config/config.yml
sylius_core:
# driver: doctrine/orm
classes:
user:
model: Acme\Bundle\Entity\User
sylius_resource:
resources:
sylius.userdata:
driver: doctrine/orm
classes:
model: Acme\Bundle\Entity\UserData
The above few lines also show :
The override for sylius_core with my new User class
The new resource - which is bascially just the userdata class
Now for the Doctrine Mapping (User.orm.xml):
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Acme\Bundle\Entity\User" table="sylius_user">
<one-to-many
field="userdata"
target-entity="Acme\Bundle\Entity\UserData"
mapped-by="userid" />
</entity>
</doctrine-mapping>
And the mapping for UserData (UserData.orm.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Acme\Bundle\Entity\UserData" table="sylius_userdata">
<id name="id" type="integer">
<generator strategy="AUTO" />
</id>
<many-to-one
field="userid"
target-entity="Acme\Bundle\Entity\User"
inversed-by="userdata"
join-column="userid">
<join-column name="user_id" referenced-column-name="id" nullable="false" />
</many-to-one>
<field name="name" type="string" length="150" />
<field name="datetime" type="datetime" />
</entity>
</doctrine-mapping>

EF 4.0 POCO magic doesn't work-- No changes detected

I can't seem to update my database from disconnected poco objects. In this example, I fetch an ApplicationUser object, update varchar(100) field SSOID, but no changes take effect. Even when I refetch the object in the save method, nothing gets sent to the db.
If I try to call ApplyCurrentValues, it throws
An object with a key that matches the key of the supplied object could not be found in the ObjectStateManager. Verify that the key values of the supplied object match the key values of the object to which changes must be applied.
public void Save(ApplicationUser au)
{
ApplicationUser original = context.ApplicationUsers.FirstorDefault(a => a.UserID == au.UserID);
context.ContextOptions.ProxyCreationEnabled = false; //changing this has no effect
if(original == null)
{
context.AddObject("ApplicationUsers",au); //this works!
}
else
{
///let's manually set some properties on the object I just fetched.
original.SSOID = au.SSOID;
ObjectStateEntry entry = null;
context.DetectChanges();
context.ObjectStateManager.TryGetObjectStateEntry(original.EntityKey, out entry);
//entry is still null!
context.ApplicationUsers.ApplyCurrentValues(original); //BOOM!!
}
context.SaveChanges();
return;
}
I tried everything I can think of, even making ApplicationUser implement System.Data.Objects.DataClasses.IEntityWithKey, which supposedly isn't necessary.
Here's the mapping:
<EntitySetMapping Name="ApplicationUsers">
<EntityTypeMapping TypeName="MyCompanyName.ApplicationUser">
<MappingFragment StoreEntitySet="ApplicationUser">
<ScalarProperty Name="UserID" ColumnName="UserID" />
<ScalarProperty Name="SystemID" ColumnName="SystemID" />
<ScalarProperty Name="Username" ColumnName="Username" />
<!--snip-->
<ScalarProperty Name="CreatedOn" ColumnName="CreatedOn" />
<ScalarProperty Name="CreatedBy" ColumnName="CreatedBy" />
<ScalarProperty Name="SSOID" ColumnName="SSOID" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
Are you using the straight/simple POCO T4 template, or the self-tracking entities template??
The straight POCO have no support for any change tracking whatsoever - if you want that, you need the self-tracking entities.
See resources:
Using Self Tracking Entities to retrieve and update
Working with Self-Tracking Entities
Update: I think you are quite close to the right way of doing things here. You re-load the original state of the object (I would probably add a check on a timestamp or something to make sure the object in store hasn't been changed in the meantime).
Once you've done that, I believe you just need to detect yourself what changes have happened / where differences exist between au and original; update the original accordingly, and then just simply call context.SaveChanges().
As far as I understand it, the .DetectChanges() can't work, since you're using straight POCO classes without any change tracking, e.g. your au object doesn't have any way of knowing what's been changed - you basically need to do a property-by-property comparison yourself.

hyperjaxb3 xsd:string length in JPA entity

I use Hyperjaxb3 to generate JPA entities from XSD schema. I have a xsd:string type that I want to use for description text (text area in the UI):
<xsd:complexType name="Description">
<xsd:simpleContent>
<xsd:extension base="**xsd:string**">
<xsd:attribute name="abc" type="xsd:NCName" use="optional" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
Hyperjaxb3 generates class (entity) Description with attribute value, annotated like this:
#Basic
#Column(name = "VALUE_", **length = 255**)
public String getValue() {
return value;
}
The questions I have:
I saw that if I put xsd:maxLength restriction on xsd:simpleType, JPA #Column.length has the value of maxLength. How can I set xsd:rescriction on xsd:simpleContent that is xsd:extension of xsd:string? Do I have to define a complexType with xsd:resctriction that I will extend? And if yes, will Hyperjaxb generate #Column.length by my restriction. I tried following:
<xsd:simpleType name="DescriptionParent">
<xsd:restriction base="xsd:string">
<xsd:maxLength value="4096" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="Description">
<xsd:simpleContent>
<xsd:extension base="DescriptionParent">
<xsd:attribute name="abc" type="xsd:NCName" use="optional" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
But the JPA column length is still 255.
Is it also possible to set in my JAXB customization (*.xjb file) the lenght of the column for given type (somehow let hyperjaxb know that this is the orm I want to use for my specific type)? Or is it totally out of the way and xsd:maxLength should be used (above) I managed to set it globally for Hyperjaxb customization:
Thanks for your help.
Second question: yes, you can configure global type mappings for simple types.
See Per-type customization for single properties.
First question: it seems to be a bug/missing feature, please file an issue here.

Why is an XSD element of type s:date becoming a string when generating a Service Reference?

I'm trying to create a new Service Reference from a WSDL and all of the properties I expect to be DateTime instead of string.
For example, this xsd definition for Contact:
<s:complexType name="Contact">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Address" type="tns:Address" />
<s:element minOccurs="0" maxOccurs="1" name="Email" type="s:string" />
...
<s:element minOccurs="1" maxOccurs="1" name="BirthDate" type="s:date" />
</s:sequence>
The type of BirthDate is s:date, but the generated type (in Reference.cs) is a string.
internal partial class Contact : object, IExtensibleDataObject, INotifyPropertyChanged
{
[OptionalField]
private MembershipMgmtMediator.Address AddressField;
[OptionalField]
private string EmailField;
private string BirthDateField;
}
If i create a web project and add it as a Web Reference instead of a Service Reference, it correctly becomes a DateTime. I assume that has something to do with the way wsdl.exe and svcutil.exe work behind the scenes, but regardless, I'm stuck on trying to figure out how to correctly get Visual Studio to recognize that this property should be a DateTime.
There is some good info in these questions: How to generate xs:Date in WCF OperationContract parameter and Best practices for DateTime serialization in .NET 3.5.
As Alex states in his comment to the question, WCF does not support xs:date types. However, it is perhaps more accurate to say that the default DataContractSerializer does not support that type, while the above questions indicate that the XmlSerializer can handle it.
See this link for a DataContractSerializer against XmlSerializer comparison.
If I run:
svcutil http://my_web_site?wsdl /ser:XmlSerializer /d:C:\temp
Then a WSDL fragment like this:
<s:complexType name="Contact">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="BirthDate" type="s:date" />
</s:sequence>
</s:complexType>
Has this class generated:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/")]
public partial class Contact
{
private System.DateTime birthDateField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(DataType="date", Order=0)]
public System.DateTime BirthDate
{
get
{
return this.birthDateField;
}
set
{
this.birthDateField = value;
}
}
}
That svcutil invocation produces two files: Service1.cs and output.config. If I include the code file in the project and add the system.serviceModel bits into the configuration file (i.e., web.config or app.config) I can then call the service as normal. For example:
Service1SoapClient client = new Service1SoapClient("Service1Soap");
var contact = client.GetContact();
This approach is not without disadvantages. The Service1.cs file is markedly different if generated without the /ser:XmlSerializer parameter, where you will get additional classes such as WebMethodNameRequest, WebMethodNameRequestBody, WebMethodNameReponse, WebMethodNameReponseBody and so on. If these classes are important in your interactions with the service, my approach may not work for you.
Edit:
In terms of nullable properties, there is some good information in this question: svcutil.exe - Proxy generated not allowing for nullable fields
To get a property nullable in the generated proxy class, the nillable field needs to be set in the WSDL. So something like this:
<s:element minOccurs="0" maxOccurs="1" name="SomeProperty" type="s:date" nillable="true" />
Would generate a property called public System.Nullable<System.DateTime> SomeProperty in the proxy class.
However in your case you can use the SomePropertySpecified property to indicate the presence or absence of the property. These kinds of properties are generated when you have minOccurs="0".
In terms of date formatting I'm not sure. xs:date values are intended to be yyyy-mm-dd with optional timezone information (w3.org). If Oracle is expecting dates in a different format then I wonder how they can be xs:date values at all.
Is there any documentation or other information you can provide regarding the service you are trying to consume?
Edit 2:
I am a little unclear on exactly what "Dates must be in the database format." means in the Oracle docs. If the type is an xs:date then serializing them to the database format would surely mean that it was no longer an xs:date?
Still, there are some things you try in that regard:
Force XmlSerializer to serialize DateTime as 'YYYY-MM-DD hh:mm:ss'
http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly
You may need to simply experiment sending a few queries to the web service to see just how this date business affects things.
Are you sure those *IsSpecified parameters aren't there? To use my Contact class above as the example, minOccurs=0 on the BirthDate property would give the Contact class an extra property called BirthDateIsSpecified.
Although I believe nick_w's answer covers the question quite well (and I'm awarding him the bounty), I'm providing the solution I'm going to use in my specific case, where just using XmlSerializer isn't enough. In the end, I think I'm going to go with an extension that converts DateTime objects to string, using a custom format specifier.
public static class SoapUtils
{
public static string ToOraDate( this DateTime? dt )
{
return dt != null ? dt.Value.ToString("dd-MMM-yyyy",
CultureInfo.InvariantCulture) :
}
}
// Calling a service
someDate = DateTime.Now;
service.SomeMethod( someDate.ToOraDate() );
While this is not a real solution, I think that it may work as a workaround. It is dirty and ugly, and I know that, but it may be better than having String in your code.
Since your own classes (like Address) are properly processed, you could build a simple wrapper around Date class that you would include in your project and schema. The class would have only a Date property or a field and a getter to it.