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
}
Related
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.
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
}
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.
So 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?
I have multiple SQL database tables whose names all begin with "access_".
Each table contains an "id_employees" column, and then a number of bit columns to define access to certain areas of different apps. There are a varying number of bit columns in each table, each with different names, and new tables will be added as new sections are developed.
I am using Kendo and MVC, and what I would like to do is have one view with a dropdown of all tables, and load a partial view underneath with a grid of the bits from the selected table. These would both be dynamically generated from the database, meaning we'd only have to add another table to the database, without having to modify the controlling program too.
I currently have a stored procedure which returns all access_ tables, and the columns in each. These are then put into classes similar to:
Public Class access_parent
{
public access_parent()
{
AccessParams = new List<access_params>();
}
public string TableName { get; set; }
public virtual List<access_params> AccessParams { get; set; }
}
Public Class access_params
{
public string ParamName { get; set; }
public string ParamValue { get; set; }
public virtual access_parent AccessParent {get; set; }
}
but I'm not sure this is the correct approach. I should be able to handle the Kendo and MVC code, if I could just figure out the correct way to handle the situation, but to be honest I'm lost. Is there a way to do this or am I making work for myself by trying to be too clever and ending up dumb?
In an application I'm working on, I have what are essentially a bunch of lookup tables in a database which all contain two things: The ID (int) and a Value (string).
There's only a handful of them, but I want to map all of them to a single Context which depends on the table name. Something like:
class LookupContext : DbContext
{
public DbSet<Lookup> Lookups { get; set; }
public LookupContext(String table)
{
// Pseudo code:
// Bind Lookups based on what table is
Lookups = MyDatabase.BindTo(table);
}
}
So if I create a new LookupContext("foo"), it binds against the foo table. If I do new LookupContext("bar") it uses the bar table, and so forth.
Is there any way to do this? Or do I have to create a separate context + model for every table I have?
This is more or less my first time doing this, so I'm not really sure if what I'm doing is right.
The answer we should be able to give you is to use enums, but that's not available quite yet - it's in the next version of EF. See here for details: http://blogs.msdn.com/b/adonet/archive/2011/06/30/walkthrough-enums-june-ctp.aspx
With earlier versions of EF, you can simply create a class per lookup value (assuming state as an example) and have code that looks something like the following:
public class State
{
public int StateId {get;set;}
public string StateName {get;set;}
}
public class LookupContext : DbContext
{
public DbSet<State> States {get;set;}
// ... more lookups as DbSets
}
This will allow you to use one context but will still require one class per table. You can also use the fluent API if you want your table/column names to differ from your class/property names respectively. Hope that helps!
I actually realized I was completely over complicating things beyond reason. There was no reason for storing multiple tables with two columns.
I'm better off storing my data as:
public class LookupValue
{
public string LookupValueId { get; set; }
public string Value { get; set; }
public string LookupType { get; set; }
}
Where the third field was simply the name of the table that I was previously storing in the database.
I'm still interested in the idea of mapping a single Context class to multiple tables, but I believe what I described above is the least convoluted way of accomplishing what I need.