ORA-00904 Linq generates error in SQL query for Oracle - c#

I use EF Core for Oracle and I try to get list of entities from the DbContext.
I have two model classes:
public class CssKursyModel
{
[Key]
[Column("KW_ID")]
public int Kw_Id { get; set; }
public CssTabeleKursowModel CoursesTables { get; set; }
[Column("KW_WAL_Z_ID")]
public int Kw_Wal_Z_Id { get; set; }
[Column("KW_WAL_NA_ID")]
public int Kw_Wal_Na_Id { get; set; }
}
and
public class CssTabeleKursowModel
{
[Key]
[Column("TK_ID")]
public int Tk_Id { get; set; }
[Column("TK_SYMBOL")]
public string Tk_Symbol { get; set; }
[Column("TK_NAZWA")]
public string Tk_Nazwa { get; set; }
}
but when I try to execute this statement
var t = context.CssCourses.ToList();
it returns an exception
ORA-00904: "s"."CoursesTablesTk_Id": invalid identifier
What can I do to resolve this situation?
When I changed my CSSKursyModel and add ForeignKey atributte, like this
{
[Key]
[Column("KW_ID")]
public int Kw_Id { get; set; }
[ForeignKey("TK_ID")]
public CssTabeleKursowModel CoursesTables { get; set; }
[Column("KW_WAL_Z_ID")]
public int Kw_Wal_Z_Id { get; set; }
[Column("KW_WAL_NA_ID")]
public int Kw_Wal_Na_Id { get; set; }
}
and changed method to
var t = context.CssCourses
.Include(i => i.CoursesTables.Tk_Id)
.ToList();
the error message looks like
ORA-00904: "i"."TK_ID": invalid identifier
The Column name is correct (TK_ID) but execution still ended by ORA-00904 exception
Regards

Oracle stores object (and column) names in UPPERCASE by default, unless you enclosed those names into double quotes at time of creation. Oracle people don't do that, so - if someone created the table for you, I presume they did it that way, i.e. didn't use double quotes.
In that case, you can reference column names using any letter case you want.
It means that you should try with "COURSESTABLESTK_ID" (if that Linq thing requires double quotes; I don't speak it so I can't tell). Otherwise, as far as Oracle itself is concerned, COURSESTABLESTK_ID (without double quotes) would do.
Your code would work if someone created the table as
create table some_table ("CoursesTablesTk_Id" number);
I presume that it was, actually,
create table some_table (CoursesTablesTk_Id number);
which means that
select coursestablestk_id from some_table
or
select COURSEStablesTk_Id from some_table
or
select COURSESTABLESTK_ID from some_table
would do.

In my experience, this is because you have on your code a field that does not exist in the database. The signature of this issue is that the query fails because you have a field referenced as "t".[tableName][FiledName]. When the entity framework is unable to map the field to an existing column on the database it creates a field like that.
To troubleshoot do the following:
Identify the field that is causing the problem:
Sometimes this is difficult because of nested relationships. Try adding the [NoMapped] attribute one field at a time until the error goes away.
Check for typos in the field name. Sometimes you include a field as part of a relationship (like using a linked table without any referential integrity constrain) in this case will not be typo, but just a field that does not exists.
Summing Up: Your mission is to find a field in your object that is not in the table, if there is a typo, fix it, if the field does not exist in the database but you need it, add the [NoMapped] attribute.
Hope this helps.
Regards.

Related

Entity Framework creates non-existing column in query

I face the problem that EF creates a column in the query that does not exist in the Oracle database table.
The simplified model which is created by EF looks like this (I use DB first approach):
public partial class USER
{
public int ID { get; set; }
public string NAME { get; set; }
public int PROCESS_ID { get; set; }
public virtual PROCESS PROCESS { get; set; }
}
public partial class PROCESS
{
public PROCESS()
{
this.USER = new HashSet<User>();
}
public int ID { get; set; }
public virtual ICollection<USER> USER { get; set; }
}
I set up the foreign key constraint in the oracle sql developer.
When I try to get the Users for a selected Process like this:
var users = context.Users.Where(u => u.PROCESS_ID == 0);
It produces following error:
ORA-00904: "Extent1"."R1": invalid ID
So i took a look on the produced SQL:
SELECT
"Extent1".ID,
"Extent1".NAME,
"Extent1".R1,
FROM DB.USER "Extent1"
WHERE "Extent1".R1 = :p__linq__0
Of course this produces an error because R1 isn't a column in the table. But I can't figure out where it comes from. It seems like EF can't map the foreign key properly thats why it's also missing in the generated SQL query?
Maybe someone has a tip for me :)
To follow up my comment, here is a link to the conventions.
The convention for a foreign key is that it must have the same data type as the principal entity's primary key property and the name must follow one of these patterns:
[navigation property name][principal primary key property name]Id
[principal class name][primary key property name]Id
[principal primary key property name]Id
Your convention [navigation property name]_ID isn't on the list.
Encountered the same error recently while working with Oracle using DevArt provider. Turned out it was caused by a column name being longer than 30 chars. OP mentioned that the model posted in his question is a simplified one so it still may be the case.

ServiceStack OrmLite: Use default database constraint instead of null value from data model

I'm still pretty new to these technologies. I've run into a small issue, and it's one that can be fixed by writing some lazy code...but OrmLite and ServiceStack streamline so many things, I'm wondering if there's a better way to do this.
So, I have a data model:
public class cctv_camera
{
[AutoIncrement]
public int I_id { get; set; }
public string I_sid { get; set; }
public string C_store_id { get; set; }
// .... others
}
This data model is mapped to a table, cctv_camera. There's another model (call it CamDetail) being sent to the client after some joins from this table. We are receiving back a CamDetail object from the client on a POST to save to the database and populating an instance of lp_cctv_camera with the data (new lp_cctv_camera().PopulateWith(CamDetail);).
Here's the thing: the I_sid column is a NOT NULL column with a default constraint that generates a hash for that row. It's something that the database is responsible for, so new items should not INSERT this column; it should be generated by the constraint.
Is there any way to db.Insert(lp_cctv_camera) while ignoring this column? I have tried the [Ignore] attribute on the definition, but we still need it in the definition to send existing I_sids out to the client. I really can't find anything in the docs. Any help is appreciated!
We've added an explicit [IgnoreOnInsert] attribute you can use to ignore specific properties on Insert which is available on v4.5.13 on MyGet.
Prior to v4.5.13 you can use the [Compute] attribute to get the similar behavior and ignore fields during inserts, e.g:
public class cctv_camera
{
[AutoIncrement]
public int I_id { get; set; }
[Compute]
public string I_sid { get; set; }
public string C_store_id { get; set; }
// .... others
}

ObjectContext Error with using .AddRange in EF 6

I'm trying to find some help on an error I'm getting when using the .AddRange in EF 6. I'm getting the following error.
The changes to the database were committed successfully, but an error occurred while updating the object context.
The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because
the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are
unique before calling AcceptChanges.
As the error states, my records are actually getting added to the table so I don't know where fix the error.
Doing some research I found a bunch of posts where others say that it has to do with the .edmx file and a primary key on the table. Their suggestion is basically to add the PK and then rebuild the .edmx file. This doesn't fit my scenario for two reasons, one is that I'm using EF 6 with DataBase First so there isn't an .edmx file and second is that this is mapped to and Oracle 11 DB and so the identity is created with a trigger (which seems to work when I look at the added records).
Here is my code I'm using as well as the class for the entity.
using (APIcontext db = new APIcontext())
{
if (listLostTime.Count > 0)
{
db.GROUND_HOURS.AddRange(listLostTime);
db.SaveChanges();
}
}
And the entity class
[Table("GROUND_HOURS")]
public partial class GROUND_HOURS
{
[Key]
public decimal RID { get; set; }
[Required]
[StringLength(8)]
public string EMP_ID { get; set; }
[StringLength(2)]
public string COMPANY_CODE { get; set; }
public DateTime OCCURRENCE_DATE { get; set; }
[Required]
[StringLength(25)]
public string PAY_CODE { get; set; }
public decimal PAY_HOURS { get; set; }
public DateTime INSERT_DATE { get; set; }
}
I'm looking for any suggestions.
Decorate the RID property with the attribute DatabaseGenerated( DatabaseGeneratedOption.Identity )
The problem is that entity framework isn't updating the key value RID with the store generated value prior to accepting changes. In your case, with multiple GROUND_HOURS entities created, each will (presumably) have the default RID value of 0. When EF attempts to accept changes, it recognizes than more than one entity has the same key value and complains.
Thanks to #Moho who gave the ultimate fix. This is how I changed the primary key in my entity class to work and is what I used in my application.
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RID { get; set; }
I was also able to fix it another way just to let others know. First off because this is and Oracle DB the RID (which is my Primary Key) was scaffold as a Decimal. That caused the RID to always be a 0 when I added my object to a list without specifically assigning it a value. To work around that I changed the RID property to an nullable INT and then when I created my list I set the RID=NULL.
[Key]
public int? RID { get; set; }
This is what I did when created my list.
foreach (var item in results)
{
GROUND_HOURS lostTime = new GROUND_HOURS();
lostTime.RID = null;
lostTime.EMP_ID = item.EmployeeId.ToString("D8");
lostTime.COMPANY_CODE = item.CompanyCode.Trim();
lostTime.OCCURRENCE_DATE = item.OccurrenceDate;
lostTime.PAY_CODE = item.PayCode.Trim();
lostTime.PAY_HOURS = item.Hours;
listLostTime.Add(lostTime);
}

Store dynamic fields

I'm working on a c# MVC5 EF6 project and I'm facing the following situation. I have a project model with some default properties:
public class project
{
public int Id { get; set; }
public string Code { get; set; }
public string Description { get; set; }
}
Now I want to give the user the option to add extra fields. Because I don't know how many fields they will add and what type of field they add, I cannot add free fields to the class like this:
public int FreeInt1 { get; set; }
public int FreeInt2 { get; set; }
public string FreeString1 {get; set; }
// etc. (let's hope we have enough fields)
So, I think the fields should be dynamically created (and stored per project). I was thinking of two possible solutions:
Create an extra table ProjectFields in a sort of Key - Value structure like the image below:
When using this approach, when you have thousands of projects with say at least 10 extra fields, it all adds up very quickly.
Add an extra string property to my project class public string ProjectFields { get; set; } and create logic to add extra fields in a XML or Json string and save that to the ProjectFields field.
I really don't know if I'm thinking in the right direction or that I should approach this situation in an other way?
provide the user with the interface to add columns , store his added column names in an array and use the following logic
//if we have an array
// array = ["ID","name","IP","active"];
foreach(var item as array)
{
sql = "alter table [TABLENAME] add [item] int default 0 NOT NULL"
//run this sql query using sql command and see the magic
}

How, using code-only, do I map Vertical Inheritance using multiple, existing "type" values? (Telerik OpenAccess)

I am trying to map a vertical inheritance between a base class and derived class (obviously). I am using code-only and the FluentAPI approach for which I have found almost ZERO documentation. I have found a couple of docs on vertical inheritance and code-only but very few on managing the discriminator column/value.
S​o ​I have been trying to extrapolate how to do it from a combination of this blog post and some documentation on implementing vertical inheritance using code-only. All to no avail.
You will see that I have a "Deliverables" base table and "PrintDeliverables" derives from that. There will be other derivatives coming down the road. But I figured I would start with one first.
Anyway, I naturally have models that map to the tables.
public class PrintDeliverable : BDeliverableBase
{
public String PaperItemNumber { get; set; }
public String PrinterModel { get; set; }
public Boolean? ColorOption { get; set; }
public String ProductCode { get; set; }
}
public class BDeliverableBase : BModelBase, IDeliverable, ISingleID
{
public Int64 ID { get; set; }
public String Label { get; set; }
public String Description { get; set; }
public IList<DeliverableAttribute> Attributes { get; set; }
public Int64 TypeID { get; set; }
public DeliverableType Type { get; set; }
}
public class DeliverableType : BModelBase, ISingleID
{
public Int64 ID { get; set; }
public String Label { get; set; }
public String Description { get; set; }
public IList<BDeliverableBase> Deliverables { get; set; }
}
I have standard mapping which maps the fields and types, sizes, etc. When I run it with no further additions I get the Error ...
Invalid Column name voa_class
My research uncovered that the ORM is attempting to update a "discriminator" column with a value that will tie the base table and table with the derived data together. I learned that I can change the name of the column it uses, which I did in the BASE CLASS mapping (BDeliverableBase). I changed it to use the "DeliverableTypeId" column since the DeliverableType indicates which TYPE of deliverable it is. Since each TYPE will have it's own derivative table this would be an appropriate value to associate which derivative table to use.
MappingConfiguration<BDeliverableBase> map = new MappingConfiguration<BDeliverableBase>();
map.HasDiscriminator().ToColumn("DeliverableTypeId");
It appears to like this better but it wants to insert this crazy number (ex// 612274703-854) into the DeliverableTypeId column which, of course, being a foreign key to the DeliverableTypes table is not allowed.
Insert of '612274703-' failed: Telerik.OpenAccess.RT.sql.SQLException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_DeliverableType". The conflict occurred in database "DB1", table "dbo.DeliverableTypes", column 'DeliverableTypeId'
I learned that OpenAccess/DataAccess generates a hash value to insert into the discriminator column. I do not want this, in fact I know that the value must be one of the IDs available in the DeliverableType. So I read in one of the docs that you could define what value to assign to the discriminator. The example applied a hard-coded value to the base class (dog and cat derived from animal) ...
animal.HasDiscriminatorValue("23");
This presented one problem ... I do not have a single value I can hard-code. It could one of MANY values present in the DeliverableTypes table. However, for the sake of proving out the concept I hard-coded the value of an existing record
MappingConfiguration<BDeliverableBase> map = new MappingConfiguration<BDeliverableBase>();
map.HasDiscriminator().ToColumn("DeliverableTypeId");
map.HasDiscriminatorValue("819");
I continued to get the identical error from before. So it doesn't appear that it was applying my hard-coded value. So ... I thought, while hard-coding the value is a little hacky it would make more sense to define that in the mapping for the derived class. That would resolve my hard-coded issue since ALL instances of that derived class WOULD indeed be of the same DeliverableTypeId. So I tried ...
MappingConfiguration<BDeliverableBase> map = new MappingConfiguration<BDeliverableBase>();
map.HasDiscriminator().ToColumn("DeliverableTypeId");
MappingConfiguration<PrintDeliverable> map = new MappingConfiguration<PrintDeliverable>();
map.HasDiscriminatorValue("819");
This resulted in the Error
Insert of '612274703-857' failed: Telerik.OpenAccess.RT.sql.SQLException: String or binary data would be truncated.
So I got a different error but still the same poblem. This type it was trying to stuff the ORM generated discriminator value (instead of my 819) into what I am assuming is my defined discriminator column (DeliverableTypeId), although the different error makes me suspicious that it was targeting a different column.(?)
In an effort to not drag this out too long I have tried several combinations of where to these "HasDiscriminator" and "HasDiscriminatorValue" assignments go but always end up with one or the other of these errors. So the question is ...
How, using code-only, do I map Vertical Inheritance using multiple, existing "type" values?

Categories

Resources