LINQ query a list inside a record - c#

EDIT
Turns out EF wont map List strings to a table. So to fix it I've created a simple table with an id, a string field and a foreign Key to the Example table, then in the example table i've updated the List<> attribute to point to this table. ...I think I had a brain fart. sorry all.
I've tried the other questions but I'm still getting the same error.
I have a table with the following:
public class Example
{
public Example()
{
ExampleList = new List<string>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<string> ExampleList{ get; set; }
}
Now when I go to query the database, I want to return back entries that contain "imastring" in their ExampleList I'm currently using:
var test = db.Examples.Where(c => c.ExampleList.Count(z => z.Contains("imastring")) == 0).ToList();
However, this query brings back the following error:
The specified type member 'ExampleList' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
I can't figure out whats wrong, what am i missing guys?
For clarity
I'm trying to bring back all "Example" record whos "ExampleList<>" contains the string "imastring"

You cannot store in database list of string type (or primitives). You need to create for example ExampleTable class with id and string value. Or keep whole list in one property (for example strings separated with ';') and parse given string with split. Or serialize list to json and save as string property.

Related

ORA-00904 Linq generates error in SQL query for Oracle

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.

Loop through strongly type fields Entity Framework c#

I am trying to come up with a neat solution for this problem to make it scalable. I've got a DataTable dt, which has its structure read from a database. I want to be able to correctly map this data into the correct fields using Entity Framework and allow the code to function even if columns are added or deleted.
using (Entities db = new Entities())
{
foreach (DataRow dr in dt.Rows)
{
var result = db.myTable.SingleOrDefault(e => e.Email == dr["Email"].ToString());
foreach (SourceToDestinationMapping s in mapping)
{
// want to do something like this
result[s.DestinationColumn] = dt[s.DestinationColumn];
// instead of this
result.Name = dt["Name"].ToString();
result.Address = dt["Address"].ToString();
// all field mappings
}
}
}
Is this something that is possible to do? Or do I need to make code changes every time a new column gets added/removed? If this isn't something that works then I can switch to doing something like this without Entity Framework.
Edit:
Example would be:
1, EmailAddress, Email, 1
public partial class SourceToDestinationMapping
{
public int MappingId { get; set; }
public string SourceColumn { get; set; }
public string DestinationColumn { get; set; }
public bool Active { get; set; }
}
Since Entity Framework works with objects you'd need to use reflection to get and set properties without knowing which properties you need to operate on, and it can get pretty complicated if you have many types that you need to handle. So basically examine the type of the object you're looking at, get its list of properties, and search for columns with the same name as the property (or some other convention you have) in the data table row. But again, you'll need to handle the type conversions, if the property is an int you need to get the cell value as an int etc.

How to create dynamic Linq Select Expression with anonymous objects

Am using Entity Framework to run a query on a table. However, i need to get select columns only.
class MyEvent
{
public string Name { get; set; }
public int Id { get; set; }
virtual Stage EventStage { get; set; }
..... more columns .....
}
class Stage
{
public string Name { get; set; }
public string Location { get; set; }
..... more columns .....
}
I can write an IQueryable to return these as
dbContext.MyEvents
.Select(s =>
new {
Name = s.Name,
Id = s.Id,
EventStage = new
{
Name = s.EventStage.Name,
Id = s.EventStage.Id
}
}
)
.ToList();
This works as expected, giving me just those columns am interested in.
Now, I need to construct that 'Select' call dynamically using Expression tree, something like here.
How can I achieve that? Is it feasible to construct an anynomous object, like above, via expressions?
EDIT:
The use case for me is that I have a generic dB context class which takes a list of columns as strings to be fetched. In the past, we were returning all columns, ignoring that input list. So, now I need to dynamically generate the select statement to return only the required subset of columns, which can either be done via anonymous object or a dynamically created DTO.
Thanks
Maybe you can use something like the ToDynamic method from here:
https://gist.github.com/volak/20f453de023ff75edeb8
A possible usecase for this problem:
Let the user select the columns to display and query only those selected columns, so you don't query always the whole entity from the database.
Define a strongly typed object and return that. I would avoid using a dynamic object.
Note: you can't return an anonymous object.

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
}

ServiceStack not using custom converter for NodaTime.Instant

In an effort to improve performance, I recently added some denormalized SQL views to our database and created some query models that correlate. Everything is working great except for one thing -- ServiceStack Ormlite isn't using my custom type converter for some of the query model fields and I can't figure out why. What's really confusing is that it is using the converter for the model that correlates to an actual table.
I've confirmed that the field names correlate to columns being returned by the database. I've confirmed that the SQL query Ormlite is constructing includes the fields in question. I've confirmed that the data being returned from that SQL is valid. But for some reason Ormlite never hits the FromDbValue method in my converter.
Here's a simplified version of what I'm doing:
Write Model
public class Session
{
[AutoIncrement]
public int Id { get; set; }
public Instant SessionTime { get; set; } // <-- this is populated properly
// -- other fields --
[References(typeof(User))]
public int UserId { get; set; }
[Reference]
public User User { get; set; }
}
Query Model
public class SessionQueryModel
{
public int Id { get; set; }
public Instant SessionTime { get; set; } // <-- this IS NOT populated
// -- other fields --
public int UserId { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
}
The write model correlates to a table named Session. The query model correlates to a view called SessionQueryModel that already has the User table joined in and retrieves the name fields.
My Instant data is stored in a DATETIME2 field, and I register my custom converter properly. If anything were wrong there, the write model wouldn't successfully be hydrated.
I can't for the life of me figure out what's going on. I can't see any difference between the two, the field names match up, etc. The only thing I can figure is that Ormlite for some reason can't glean the type from a view in the same way it can from a table. Any ideas what might be causing this?
UPDATE
It appears that it's not just my Instant fields. There are a handful of other fields that aren't being populated as well, even though they're in the data with names matching the properties in the query model POCO. There doesn't seem to be any rhyme or reason. Some of these are simple VARCHAR columns mapping to string properties.
Now I'm really confused.
I figured it out. The class in question had two enum properties. One was of type SessionStates and the other SessionStatuses. I guess I didn't pay attention to the Intellisense entry originally, and the similar names made it not so easy to see.
Anyway, the enum values are stored in SQL as strings, not integers, and when ServiceStack was mapping, I can only assume the inability to parse the string to an enum value caused all mapping to cease.
Demis, if you're out there, this looks like it's probably a bug. I would think the system should throw an error if there was a parsing error as opposed to simply stopping mapping.

Categories

Resources