Cannot generate C# class from PostgreSQL view using Npgsql + EF6 code first - c#

I am trying to use entity framework code first method to connect to PostgreSQL database, and when I use entity data model wizard in visual studio to generate C# class from database, it can generate classes for each table in database successfully, but the views in database cannot be generated.
(source: linearbench.com)
(source: linearbench.com)
Can someone told me where I did wrong? I use Entity framework 6.1.3, with Npgsql 2.2.5. PosgreSQL database is version 9.3.6 installed on a Ubuntu server.
Thanks

I know this question is a little bit old now, but ill chime in here for anyone else who may be looking for solutions here. My answer may not be exactly what the question was looking for, however, it has sufficed as a work around solution for me.
The problem with views is that entity framework has a hard time determining the primary key column for them. In Sql Server, you can use ISNULL() function to trick EF into thinking that the column is a key column, but the equvilant coalesce() function in postgres isn't good enough for EF. I also tried generating auto-incrementing row id column, joining to other tables with primary keys, etc; no luck with any of these.
However, something that has just about emulated the functionality that I needed as far as being able to query my views into my view objects is to just extend your context class with functions that call Database.SqlQuery and return it as a Queryable
For example:
Suppose a view in your database, "foo", with columns id, bar, baz. You can write your own POCO to hold the view data like so
public class foo
{
public int id { get; set; }
public string bar { get; set; }
public string baz { get; set; }
}
and then extend your context class with a partial class definition like this
public partial class FooContext : DbContext
{
public IQueryable<foo> foo =>
this.Database.SqlQuery<foo>( "select * from foo" ).AsQueryable();
}
And then you can query it from your context just the same as any other table
context.foo.where( x => id > 100 ).toList(); //etc,etc
You wont be able to do inserts or use any of those extra capabilities that usually come with the standard DbSet, but Views are typically used as read-only queries anyways (unless youre using some special insert triggers)...
But this gives you a base call that will query the entire view, and it doesn't hit the database because its left as a queryable, so you're free to call any other LINQ extensions on it such as Where to filter it to the results you want.
I migrated from sql server to postgres sql using npgsql lib, and this fix allowed my views to work without having to make any changes to my programs codebase, just as if nothing had changed at all, and despite the fact that the edmx would not generate my view objects due to lack of a (discernible) primary key.
Hope this helps!

Related

How to Remove a Attribute of a Property in a Class

I want to do some changes in a table that is already exist(i am using sqlite). I want to remove a Attribute of a property in a class. Remove [Required] attribute. How can i do that, what should i change, should i some changes in DbContext or migration folder or what commands can i use in package manager console.
public class Appointment
{
[Required]
[MaxLength(50)]
public string Company { get; set; }
This is a good example of why it is better to use fluent API then attributes to specify your database: you want the same class to be used in a different database.
The DbContext defines the database: what tables are in it, how do the tables relate towards each other, what classes do represent the tables, and what are the constraints to the tables.
For instance, maybe in one database you want Company to have a MaxLength of 50 characters, in another database you might desire a length of 100 characters. Some databases need a simple DateTime, others require a DateTime2. Or maybe you want a different precision for your decimals?
Hence it is usually better to specify the database statistics where it belongs: in the definition of the database, which is the DbContext.
Back to your question
It depends a bit on the entity framework that you are using on how the database reacts if during migration you use remove the Required attribute and move it to fluent API. I guess it is best to experiment with it.
In OnModelCreating, or the migration equivalent of it, you will have something like:
var entityAppointment = modelBuilder.Entity<Appointment>();
var propertyCompany = entityAppointment.Property(appointment => appointment.Company);
propertyCompany.IsOptional()
.HasMaxLength(50)
...; // other non-default specifications of Company
// like columnName, IsUnicode, etc
When migrating the statements might be little different, but I guess you get the gist.

Dynamic Property Binding in EF?

Apparently, the same columns value-type differs across environments for the same database entity (table) & they refuse to update to a common type - don't ask why!
I am using Entity Framework (version 6.1.3) alongside a Unit of Work for data-access. And, as you can guess, I am getting errors because the DEV & the QA database definitions do not match for the same column.
THE GOOD NEWS:
We do not save into these particular tables - we only query those particular tables.
SAMPLE MODEL:
There are obviously more columns than this.
public partial class Transactions
{
[Key]
public int TransactionId { get; set; }
public float Amount { get; set; } //<-- This type differs between database environments
}
MY QUESTION:
Is there a way to dynamically bind the value for a column in Entity Framework?
Or, can I treat it as a dynamic under-the-hood...and transform it to an expected type which is constant to my model?
OPTIMALLY - AND TO BE CLEAR:
I would like to define the property concretely, and have Entity Framework "convert" from the unknown type & into the concrete type - but under-the-hood.
Any help is appreciated.
If the types of the columns are compatible (i.e. are all numbers) you can have a common type on the class then disable model checking (and migration). This solution could work on some DBMSs and not on some Others (depends on the provider).
You can write a view with cast and map it in your model (and not the table).
You can write a direct query with EF (official docs https://msdn.microsoft.com/en-us/data/jj592907.aspx similar to Dapper solution with same advantages and defects, in your case lazy load won't work).

EF6 ignoring [Table] and [Column] in entity classes

I used EF6 Database First tools to generate C# classes for 2 tables from my database, then (as advised in the blog post that helped me through the steps to do that) copied the resulting .cs files into a new project. I made a few edits to the classes to support sensible names in my C# code. Here's a snippet of one of the classes with "LongTableName" replacing a strangely long name used in the database.
namespace RidesData
{
[Table("LongTableName")]
public partial class PhoneData
{
[Key]
[Column("LongTableNameID")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Column("LongTableNameAccountID")]
public int AccountID { get; set; }
// more fields
}
}
I am not in control of the table names, nor the fact that the many of the column names have the table name as prefixes. But the Code First ideas in EF6 should, I thought, let me use reasonable class and field names despite that. (The Database First code generator did a good job of adding code to OnModelCreating to specify that none of the columns corresponding to C# string data used Unicode.)
My model (generated by the EF6 tools and that inherits from DbContext) includes (after some renaming by me)
public virtual DbSet<PhoneData> PhoneRecs { get; set; }
and I thought all would be fine when I created an instance of PhoneData, populated it, and did
Model.PhoneRecs.Add(phoneData);
but the first thing that happened when I ran the code -- well before any call to SaveChanges() -- was that EF generated CREATE TABLE statements for the two tables; the table corresponding to the snippet above was named PhoneDatas (not using the specified table name) and the column names were the same as the field names in the class (not what was specified in the Column(...) attributes).
Of course the table I had specified did not need to be created. EF just had to grok that I wanted to use the table and column names I had specified via attributes.
I did not expect this failure of explicit Code First attributes. Does anyone have a clue why this isn't doing what I want, or how to fix it? (Do I have to do something to specify the table & column names in OnModelCreating as well as -- or instead of -- the attributes?)
Note that the project that I copied these classes into had never "seen" the database before. There are no vestiges of any "models" left over from tooling having looked at the database. Also, I hope it does not matter that I've tried to keep things on .Net 4.0 (avoiding going to 4.5 in this code).
Any assistance would be appreciated.
I'm not a big fan of DataAnotations either. Use EntityTypeConfiguration. It gives you the naming flexibility I think you are looking for.
Example.
public class PhoneData
{
public int ID {get;set;}
public string SomeProperty {get;set;}
}
public class PhoneDataMap : EntityTypeConfiguration<PhoneData>
{
public PhoneDataMap()
{
ToTable("WhatEverYou_Want_to_call_this");
HasKey(m => m.Id);
Property(m => m.SomeProperty).HasColumnName("whatever").IsRequired();
//etc.
}
}
Then in your on ModelCreating you add
modelBuilder.Configuration.Add(new PhoneDataMap());
On a side note, if you are having trouble with pluralization of your table names you can add this to OnModelCreating as well
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

Entity Framework native sql mapping to class

I got a code first EF and I want to use native sql for the more complex select statements.
When I try to execute:
using (VaultsDbContext db = new VaultsDbContext())
{
var contracts = db.Contracts.SqlQuery("select * from Contracts").ToList<Contract>();
}
I got:
Cannot create a value for property 'MetaProps' of type
'DskVault.Models.DbModels.MetaProps'. Only properties of primitive or
enumeration types are supported.
MetaProps is a class that holds deleteflag, creator etc. and it's a property of all my classes. It's not mapped to a different table, every table has deleteflag, createor, etc.
public class Contract
{
public long Id { get; set; }
...
public MetaProps MetaProps { get; set; }
}
Is there a way to map from the native sql to the class if the class contains a complex type or does EF not support that? Also what if the complex type is entity mapped to another table(join)?
Edit:
Version: Entity Framework 6
I know from experience not all the fields in your table have to be contained in your model. This is a good thing when it comes to installing updates into production.
Have you tried reverse engineering your tables on a SEPARATE temporary project using the Entity Framework Power tools? This is a Nuget package that I have found to be extremely useful in code first programming. Reverse engineering will overwrite existing files, so make sure not to do this on your live code.

Entitiy Framework, use same model for two tables with same layout but different table names

I have two tables that have the same layout -
Report Table
ID
ReportCol1
ReportCol2
In another database I have
Reporting Table
ID
ReportCol1
ReportCol2
I want to use a single entity model called Report to load the data from both of these tables.
In my context class I have
public DbSet<Report> Report{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ReportMap());
}
In my call to the first database Report table I get the results as expected.
I change the connection string to point to the second database, but I can't change the name of the table in the table mapping.
I don't want to use stored procs for the reason outlined in my comment.
What can I do, short of the tables names in the database(that is not an option).
Have you tried this fluent API modelBuilder.Entity<Report>().ToTable("Reporting"); ? You may need to write this so it conditionally does this based on which database you are connecting to. You may need to have your configuration allow you to say "DatabaseA uses this mapping and connection string", and "DatabaseB uses this other mapping and conenctions string", and rather than changing the connection string, you specify which database by some name/key, and your app looks up that name to determine which mapping code to run.
if(dbMappingconfig == DbMapping.A)//some enum you create
{
modelBuilder.Entity<Report>().ToTable("Reporting");
}
If your goal is to be able to pass these entities to other methods like DisplayReport(Report r) so that you don't have to duplicate code, you could have both Reporting and Report classes implement a IReport interface.
EF also supports inheritance hierarchies, so you could have them inherit from the same class, BUT I havfe a strong feeling that will not work across databases.
If the OnModelCreating doesn't rerun, it's probably already cached. Put modelBuilder.CacheForContextType = false; in there so it doesn't cache it in future, and to clear the current cache I think you can just do a Clean+Rebuild. This will come at the price of rebuilding the model everytime instead of reusing a cache. What you'd really want is use the cache up until the connection string changes. I don't know of anyway to manually clear the cache, but there might be a way. You can manage the model building yourself:
DbModelBuilder builder = new DbModelBuilder();
// Setup configurations
DbModel model = builder.Build(connection);
DbCompiledModel compiledModel = model.Compile();
DbContext context = new DbContext(connection, compiledModel);
But that will introduce additional complexities since you will need to manage the caching yourself.
While searching on this, I came across this that looks like they are trying to accomplish the same thing, as well as having gone down the same page, see Final section in question: How to map an Entity framework model to a table name dynamically
Are you able to create the same named view in each database and map to that instead of a variable table name?
I have 2 copies of tables with different names in my solution and deal with that by having 2 contexts and 2 sets of map files (generated text templates)

Categories