Get EF Table by type (parameter) - c#

I have this very old database with all the tables named like this ANAGT*postfix* and all the columns are namede like this *prefix*_*column name*.
I have to query all the tables with the same query more or less, but obviously the names of the columns are all different so I would have to do some trick with a sql statement with the strings, but I prefer to get a strong typed exception in case of errors using the EF.
So I've created some interfaces and implemented them on partial classes from the EF model
public partial class *table name* : IIdentificable, ICountabile {}
IIdentificabile means that there's a method with a common name that gets all the ids (instead of query *prefix*_ID), so when I'll have to query the table I'll just have to do
var result = from elem in myContext.[Table]
where elem.GetId() == 1
select elem;
I've created a generic method that gets all the types from a certain interface (IIdentificable for instance) and now I have to get the EF table by type.
var tablesType = typeof(myModel).Assembly
.GetExportedTypes()
.Where(t=>t.IsAssignableFrom(typeof(T)));
foreach(Type t in tablesType){
var query = from elem in myContext.GetTable(t) //and here's what I can't do
select elem.GetId() == 1
select elem;
}

I think another approach may be better. In the EF Model you can rename the C# Objects and properties. Using the properties of a selected property in the model, you can change the Name to get rid of the prefix. Similarly, the properties of a selected table in the model allow you to change both the Entity Set name (the name of a collection of them) and the Name of the C# class. The names of the underlying database tables and columns aren't affected.

Related

HasDbFunction, table value function without a mapped entity class

Everything I've found so far, if you are calling a table value function the return value must be an IQueryable. For example:
public IQueryable<AlbumsByGenre> ufn_AlbumsByGenre_ITVF(int genreId)
=> FromExpression(() => ufn_AlbumsByGenre_ITVF(genreId));
Most often when I'm using a table value function the table type that is returns is a DTO. That is, it doesn't match any actual tables in the database. Here is a example:
CREATE FUNCTION dbo.ufn_AlbumsByGenre_ITVF(#GenreId int)
RETURNS TABLE
AS
RETURN(
SELECT
ar.ArtistName,
al.AlbumName,
g.Genre
FROM Genres g
INNER JOIN Albums al
ON g.GenreId = al.GenreId
INNER JOIN Artists ar
ON al.ArtistId = ar.ArtistId
WHERE g.GenreId = #GenreId
);
Creating an entity for the return type results in an unnecessary, unused, and unwanted table in the database. In this instance the table name is "AlbumsByGenre".
Is there any way to have the return type be an unmapped type to prevent the unnecessary table?
Currently (as of EF Core 6.0) the type must be a model type (with or without key). There are plans for Raw SQL queries for unmapped types for EF Core 7.0 which might or might not allow the mapping you are asking for.
So for now your type must be registered in the model (cannot be unmapped). But creating associated table is not mandatory and can be avoided by configuring it with ToView(null), e.g.
modelBuilder.Entity<AlbumsByGenre>()
.HasNoKey() // keyless
.ToView(null); // no table or view
For me .ToView(null) still generates a table for the AlbumsByGenre.
My workaround is to map this type to the raw SQL query (tested on Entity Framework Core 6.0.9). Here I call the function with default parameters (for the author's case, the NULL value should be then allowed).
modelBuilder.Entity<AlbumsByGenre>()
.HasNoKey()
.ToSqlQuery("SELECT * FROM ufn_AlbumsByGenre_ITVF(NULL)");
Yes just create a class that has ArtistName, AlbumName and Genre however it should not be an IQueryable just a List<AlbumsByGenre> or IEnumerable<AlbumsByGenre> or an ICollection.
IQueryable is a delayed querybuilder for a table or view.
SQL functions results are not further queryable in SQL Server, so just drop the IQueryable.

C#, EF: Map [NotMapped] value from Sql Query

I'm using Entity Framework. I currently have an attribute that is labeled [NotMapped] in my model class. I'm also using a query to bring back that value (from a view, which is why it's not mapped).
var list = context.Database
.SqlQuery<SomeModel>("SELECT NonMappedField, anotherfield FROM SomeView")
.ToList()
Is there a way I can hint to C# that for this instance, it should map the column from the raw query to my models?
I would have more things showing what I've tried, but I don't have the slightest clue of what to do next, other than build my own mapper and that seems like a very brittle solution.
Possible X/Y Problem:
My a data model has a Parent/Child relationship. The Child can be a child of multiple models,necessitating the use of a join table ParentChildJoin. When I do
context.Database.Parent.Where...Include( n => n.Children ).ToList();
I run into query timeouts for a pathetically small number of rows. So I had the bright idea of joining the ParentChildJoin table with the Child table in a View and retrieving the children that way. This works, but I need some way to map the retrieved Child objects to their Parent.
This is where the NotMapped field comes in. I can create a NonMapped field on my model, and then when I retrieve from my View, I can store the ParentId there. From there, I can associate the Child objects with the correct parent.
So that's how I go here.
Either the field is mapped or it isn't, you can't have it both ways!
Take a look at AutoMapper and the AutoMapperEF extension. The EF extension is clever enough to realise that a model that only has a selection of fields from a query will only have those fields in the generated SELECT. You could have several different models for the same query, each only returning the fields required for that model.
What you can do (without changing model) is to concatenate NonMappedField+"_"+anotherfield as anotherfield before load.
After FromSql load, you can split NonMappedField and anotherfield back.
var query = "SELECT [Id], CONVERT(VARCHAR(1024),[NonMappedField]+'|'+[anotherfield]) AS [anotherfield] FROM myView";
var list = _context.SomeModels.FromSql(query)
.Select(i => new SomeModel {
Id = i.Id,
NonMappedField = i.anotherfield.Substring(0, i.anotherfield.IndexOf('|')),
anotherfield = i.anotherfield.Substring(i.anotherfield.IndexOf('|')+1)
}).ToList();

How to find the mapping tables in from the EF generated Classes

I have a mvc 4 application which is entity framework database first based. Therefore lots of the classes are generated based on database tables via EF.
Currently, I created a method to retrive data from a table and display them in a dropdownlist, which works fine. However, I am thinking to modify that method to a generic type method, and passing the class type as the method parameter, and I would like c# code to find the mapping table in the database and retrive the data.
Following is my modified method
Thanks for your helps!
public static SelectList FromDbTableToSelectList<T>() where T: class
{
var db = new TableEntities();
//find the mapping database table
Dictionary<Guid, string> dic = db.MappingTable.ToDictionary(v => v.tableColumn1, v => v.tableColumn2);
return new SelectList(dic, "Key", "Value");
}
I don't understand your what your code does. However, there is a trick to find mapping table name (Entity Set Name in EF glossary) of an entity.
Suppose that you have a table in your db named Products. If you create your model with the Pluralize and singularize option checked, EF will create an entity class named Product.
Then, whenever you perform a query, EF naming convention thinks that your table name is dbo.Products. This is a general rule - in fact a naming convention.
From the other hand, if you uncheck the Pluralize and Singularize option, EF creates an entity class named Products for you and in this case, the class an the table have same names.
So, according to the selection of P&S option, you can infer table names from entity names and you don't need any code for it...

Accessing a Common Code Value Table in Generated EF Models

I have a database that uses a custom model for recording lookup valus (i.e. states, types, etc.). So across all of the database tables, there are various columns called something like state_cdv_id which would store an integer and reference the code_value table to get that state's value (i.e. "CA", "AK", etc.).
I would like to map my EF model so that I can access the code values for all of these fields, and I don't want to have to do it manually in partial classes for EVERY entity... that's a lot of repetition. So I want to be able to access my code values like: MyPerson.State and get back the string "CA" for example.
Here's what a single getter would be that I would have to repeat many times if I were to do it manually:
public string State
{
get
{
MyEntityContext c = new MyEntityContext();
return c.CodeValues.Single(cv => cv.Id == RecordStatusCdvId).Value;
}
}
I don't know what the best approach would be: change the T4 templates, add property attributes to certain fields and then programmatically add a getting to those, or something else.
Any help?
If there is a 1:1 relationship between the entity and the code_value table the entity should already have a State property, which by default which will be null by default, you could then fill it in by using an Include on your DB queries:
var foo = context.MyEntities.Include( x => x.State);
Your sample code is terribly wrong because it makes your entity dependent on the context (moreover you don't dispose it). Whole POCO approach just to avoid this (POCO T4 generator and DbContext T4 generator).
If you have relation to lookup table in your database EF will crate for you navigation property. If you don't have such relation in the database and you are using EDMX file you can still create such relation in your model and you will again get navigation property to lookup table. Once you have navigation property you can simply do:
string code = myEntity.State.Code;
But the navigation property must be loaded either by eager loading (as #BrokenGlass described) or by lazy loading.
If you don't like the idea of navigation property and you still want State property to show just code of the state you must understand what does it mean: If you map the entity that way it will be read-only because EF will not be able to transform compound entity back to real tables which must be updated. It is possible to map the entity the way you want but it is considered as advanced (and mostly not needed) scenario which works only if you have EDMX file (not with code first approach). The choices are:
Create database view and map the view to a new entity
Create DefiningQuery manually in EDMX (opened as XML) file and map it to a new entity (once you do that you cannot update your model from database or generate database from model any more)
Create QueryView manually in EDMX (opened as XML) file and map it to a new entity (this requires original entities to be already mapped)
You will have to do that for every table where you want such mapping. Anyway whole that complexity with manually changing EDMX is not needed because you can simply create custom classes like:
public class SomeViewModel // I suppose your main target is to have codes in presentation layer
{
public string SomeData { get; set; }
public string State { get; set; }
}
and use projection query
If you have navigation property:
var data = from x in context.SomeEntities
select new SomeViewModel
{
SomeData = x.SomeData,
State = x.State.Code
};
If you don't have navigation property
var data = from x in context.SomeEntities
join y in context.LookupValues on x.LookupId equals y.Id
select new SomeViewModel
{
SomeData = x.SomeData,
State = y.Code
};

Querying conceptual model with Entity SQL

Thought I read somewhere that you in fact can query your conceptual model with Entity Sql, using string based queries as such:
class DBSetTest<T> : List<T>
{
DBEntities db = new DBEntities();
public DBSetTest()
{
ObjectQuery<T> test = new ObjectQuery<T>("SELECT Name FROM Sessions WHERE Name = 'sean'", db);
foreach (var v in test)
{
this.Add(v);
}
}
}
Where 'Sessions' is a custom Entity Type I defined with a 'DefiningQuery'. I would otherwise query it with normal linq syntax. Does Entity SQL only query the store or can it query my conceptual model just like LINQ-to-Entities does? If so not sure I have the right syntax, since it probably isn't sql syntax. My goal is to create a sort of custom generic list here, where I can write dynamic queries against my conceptual model.
I get the following error:
'Name' could not be resolved in the current scope or context. Make sure that all referenced variables are in scope, that required schemas are loaded, and that namespaces are referenced correctly. Near simple identifier, line 1, column 43.
I think, It is not valid Entity SQL sintax,
probably you must add some keyword like this :
SELECT VALUE s.Name FROM your_ObjectContext_name.Sessions AS s WHERE s.Name = 'sean'
The error you get says that you must put it. before Name, like this:
"SELECT it.Name FROM Sessions WHERE it.Name = 'sean'"

Categories

Resources