SQLProvider Unable to cast object of type 'System.Guid' to type 'System.String' - f#

I'm using SQLProvider for making a query in F# project. In my DB I have a column which is storing GUID - 'Id' char(36) NOT NULL. And when query is made I got an error:
Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.InvalidCastException: Unable to cast object of type 'System.Guid' to type 'System.String'.
I'm using MySqlConnector as a driver.
Here is how table looks in DB
CREATE TABLE `Comics` (
`Id` char(36) NOT NULL,
`Price` double DEFAULT NULL,
`Title` char(255) DEFAULT NULL,
`Image` char(255) DEFAULT NULL,
`Description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Here is types which was generated based on DB
Here is a query
let ctx = sql.GetDataContext()
let ComicsTable = ctx.ComicsShop.Comics;
let getById (id: string) =
query {
for c in ComicsTable do
where (c.Id = id)
select c.Id
} |> Seq.head
And usage
let result =
getById "0e49d94e-76c4-44be-b2ea-38382b297c78"
Console.WriteLine(result)
Thanks for your help.

After quite some time of investigation the issue was with DB.
My Id field has type as char(36) which is converted into string. But since that column contains GUID, SQLProvider will make a query assuming that field is Guid, and it will throw an error in Runtime.
The solutions is simple enough Id columns which is containing Guid should be typed as varchar(36) then all types will be converted correctly.

Related

How to force Entity Framework 6 to generate parameters of equivalent size to their corresponding database columns

I've created a database-first EDM for a table with columns encrypted using Always Encrypted. Our business prohibits direct access to tables, so I'm also using stored procedures for all database access.
When I try to insert row, I get the following error:
System.Data.SqlClient.SqlException: Operand type clash: varchar(8000)
encrypted with (encryption_type = 'RANDOMIZED',
encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256',
column_encryption_key_name = 'XXXXXX',
column_encryption_key_database_name = 'XXXXXX') collation_name =
'SQL_Latin1_General_CP1_CI_AS' is incompatible with varchar(60)
encrypted with (encryption_type = 'RANDOMIZED',
encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256',
column_encryption_key_name = 'XXXXXX',
column_encryption_key_database_name = 'XXXXXX') collation_name =
'SQL_Latin1_General_CP1_CI_AS
The stored procedure parameter is declared as varchar(60) which matches the table definition.
Because I'm using Always Encrypted, the parameter definition must match the column definition. However, EF generates a parameter declared as varchar(8000) for this property, which violates the encryption contract.
Is there any way to force EF to use the declared parameter length?
Resolved, see description here. In this particular scenario, the EDM contains two definitions of the stored procedure: one in the StorageModels element and one in the ConceptualModels element. Setting the MaxLength attribute in the StorageModels definition resolves the problem.

How to reference enum type in entity sql

I have the following (simplified) Entity SQL query:
SELECT VALUE a
FROM Customers AS a
WHERE a.Status NOT IN { 2, 3 }
The Status property is an enumeration type, call it CustomerStatus. The enumeration is defined in the EDMX file.
As it is, this query doesn't work, throwing an exception to the effect that CustomerStatus is incompatible with Int32 (its underlying type is int). However, I couldn't find a way to define a list of CustomerStatus values for the IN {} clause, no matter what namespace I prefixed to the enumeration name. For example,
SELECT VALUE a
FROM Customers AS a
WHERE a.Status NOT IN { MyModelEntities.CustomerStatus.Reject, MyModelEntities.CustomerStatus.Accept }
did not work, throwing an exception saying it could not find MyModelEntities.CustomerStatus in the container, or some such.
Eventually I resorted to casting the Status to int, such as
SELECT VALUE a
FROM Customers AS a
WHERE CAST(a.Status AS System.Int32) NOT IN { 2, 3 }
but I was hoping for a more elegant solution.
Oooh, you are writing Entity SQL directly. I see... Any reason you aren't using DbSet instead of writing Entity SQL by hand? Could always do
var statuses = new [] { Status.A, Status.B };
var query = context.SomeTable.Where(a => !statuses.Contains(a.Status)).ToList();

Compound key reverse engineering grails pulgin issue

i have this table :
CREATE TABLE `documents_revisions` (
`es_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`seq_head` int(10) unsigned NOT NULL,
`member_id` int(10) unsigned NOT NULL,
`file_id` varchar(512) COLLATE utf8_unicode_ci NOT NULL,
`save_hash` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
UNIQUE KEY `documents_rev_eis_idx` (`es_id`,`seq_head`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
When i apply reverse eng grails plugin grails db-reverse-engineer , i get this error :
Method public java.lang.String
grails.plugin.reveng.GrailsEntityPOJOClass.renderConstraints() threw
an exception when invoked on Entity: abdennour.DocumentsRevisions
However , there is no pb with the others Db tables . Indeed , Reverse engineering works fine with those tables.
Thus , i note that this plugin have a problem with compound key .
Please , Note that is a composite UNIQUE key it is not a composite PRIMARY key
This is a bug in the plugin - it assumes that all tables have a primary key and fails when the object representing that in the model is null. I released version 0.5.1 of the plugin with a fix for this.

How to specify sequence on non-id column in Grails?

I am trying to map a column in grails to a sequence, but this column is not the id.
Integer seqCol
I have tried the following code in static mapping, I'm basically just switching 'id' with 'colum'.
column name: "seqCol", generator: "sequence", params:[sequence:"SEQUENCE_NAME"]
This returns an error on save, saying that seqCol cannot be null which leads me to believe the mapping failed.
In order to change the name of the id property, you need to specify the name for the id property.
Integer seqCol
static mapping = {
id name: 'seqCol', column: 'seq_col', generator: "sequence", params:[sequence:"SEQUENCE_NAME"]
}

Mapping exception when using discriminator in Grails 2.0.0

At general I have problem with mapping: org.hibernate.MappingException: Repeated column in mapping for entity: os.comida.StoreDocumentRw column: Type (should be mapped with insert="false" update="false")
To introduce the problem: I have many document types where each document type differs just a little bit from any other. All of them have common properties: date, number, issuer etc. So I decided store all document types in one physical table (one - it's very important for me). To implement this I wanted use hibernate discriminator.
Below I'm pasting my source code. I have there a base class StoreDocument and two document types StoreDocumentRw and StoreDocumentWz.
class StoreDocument {
String type
Date documentDate
static mapping = {
table '"StoreDocument"'
version false
id column:'"StoreDocumentID"', generator:'sequence', params:[sequence:'STORE_DOCUMENT_SEQ']
discriminator column: '"Type"'
documentDate column:'"DocumentDate"'
type column:'"Type"'
}
}
class StoreDocumentRw extends StoreDocument {
String rwSpecificData
static mapping = {
discriminator value: 'rw'
rwSpecificData column:'"RwSpecificData"'
}
}
class StoreDocumentWz extends StoreDocument {
String wzSpecificData
static mapping = {
discriminator value: 'wz'
wzSpecificData column:'"WzSpecificData"'
}
}
And when I'm trying run an app I get mentioned earlier org.hibernate.MappingException: Repeated column in mapping for entity: os.comida.StoreDocumentRw column: Type (should be mapped with insert="false" update="false")
When I add type insertable: false, updateable: false to StoreDocumentRw mapping, it's still the same.
When I add type insertable: false, updateable: false to StoreDocument mapping, it's even worse:
ERROR hbm2ddl.SchemaExport - Unsuccessful: create table COMIDA2."StoreDocument" ("StoreDocumentID" number(19,0) not null, "DocumentDate" timestamp not null, "Type" varchar2(255 char), "Type" varchar2(-1 char) not null, "WzSpecificData" varchar2(255 char), "RwSpecificData" varchar2(255 char), primary key ("StoreDocumentID"))
ERROR hbm2ddl.SchemaExport - ORA-00957: duplicate column name
So I don't know where I should put this insertable/updateable thing to make it working. I'm using Grails 2.0.0 and Oracle 10g. Can anybody tell me what's wrong with my code?
Solution:
My mapping in StoreDocument was wrong. It's enough to cut String type and type column:'"Type"' and edit discriminator mapping like this discriminator column:[name:'"Type"',length:50], which in result gives:
class StoreDocument {
Date documentDate
static mapping = {
table '"StoreDocument"'
version false
id column:'"StoreDocumentID"', generator:'sequence', params:[sequence:'STORE_DOCUMENT_SEQ']
discriminator column:[name:'"Type"',length:50]
documentDate column:'"DocumentDate"'
}
}
In StoreDocument you have String type and discriminator column: '"Type"', so from your exceptions it looks like Grails is trying to create two columns of name type. Try changing the name of your String or discriminator-column and see if that corrects the issue.
To get around the issue with generating a varchar(-1) field try this: discriminator column:[name:'Type',length:10] from this JIRA GRAILS-5168. Of course, change the length to whatever you need.

Resources