entity framework code first and view mapping - entity-framework

I have a application using code first; in search section I have to gather information from 3 tables and their related tables so I made a view; and since there is no syntax for code first to create view (I think so; please let me know if I'm wrong) I used pure SQL script;
on model creating to prevent EF to create a table with same name as table (VIEW_SEARCH) I did :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<View_Search>();
}
any ways application works fine until you try to get data from the view then BANG...
The model backing the 'SearchContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269)

This error simply says that what you have in your model file is inconsistent with what you have in your database.
To make it consistent go to Package Manager Console and type Enable-Migrations, then Add-Migration yourMigrationName and Update-Database. The error should disappear.
If you want to combine data from 3 tables you can simply create a ViewModel.
Let's say you have 3 models: Book, Author, BookStore and you want to have all information in one view. You create ViewModel
public class MyViewModel
{
public Book myBook {get; set;}
public Author myAuthor {get; set;}
public BookStore myBookStore {get; set;}
}
Then you add at the top of your all-in-one-view
#model myNamespace.MyViewModel
and access items like
Model.Book.title
Model.Author.name
Model.BookStore.isClosed

I'm actually working with Entity Framework "Code First" and views, the way I do it is like this:
1) Create a class
[Table("view_name_on_database")]
public class ViewClassName {
// View columns mapping
public int Id {get; set;}
public string Name {get; set;}
// And a few more...
}
2) Add the class to the context
public class ContextName : DbContext {
// Tables
public DbSet<SomeTableClassHere> ATable { get; set; }
// And other tables...
// Views
public DbSet<ViewClassName> ViewContextName { get; set; }
// This lines help me during "update-database" command
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
// Remove comments before "update-database" command and
// comment this line again after "update-database", otherwise
// you will not be able to query the view from the context.
// Ignore the creation of a table named "view_name_on_database"
modelBuilder.Ignore<ViewClassName>();
}
}

Related

EF6 code first and VIEW

I would like to add a VIEW to the database, and query the data from this VIEW using L2E. I use migrations for maintaining database schema.
I added one class that should MAP to a VIEW columns. As an example, this class has only two properties
[Table("View_Data")]
public class ViewData
{
[Key]
public int Id { get; set; }
public int PropertyA { get; set; }
}
public class ViewDataMap : EntityTypeConfiguration<ViewData>
{
public ViewDataMap ()
{
this.ToTable("View_Data");
this.HasKey(t => t.Id);
}
}
I added ViewDataMap to OnModelCreating, as with any other Table mappings. I added DbSet ViewDatas.
When I executed
add-migration preview
it created new migration with CreateTable command. Since I do not want to create a table, but only a view, I replaced in UP() CreateTable with Sql("CREATE VIEW...")
Still, EF complains about pending changes in database, and still wants to create new migration with CreateTable()...
How can prevent EF to create new table, but use VIEW instead?
As Steve suggested in the comment, I forgot to do update-database, then all works as expected.

Unable to query new table from asp.net core web application using EF 1.0

I have developed a new asp.net Core web application using Visual Studio 2015. I am at the point where I am adding user customization options by adding additional tables to my local database. However I have been unable to add whatever EF needs to query a new table correctly. I get the following error when attempting to query the table..
Applying existing migrations for ApplicationDbContext may resolve this issue
There are migrations for ApplicationDbContext that have not been applied to the database
•00000000000000_CreateIdentitySchema
Apply Migrations
In Visual Studio, you can use the Package Manager Console to apply pending migrations to the database:
PM> Update-Database
Alternatively, you can apply pending migrations from a command prompt at your project directory:
dotnet ef database update
My table is a simple table with a few varchar or nvarchar columns. The model looks something like...
namespace MyNamespace.ColorSchemes
{
public class ColorSchemesViewModel
{
[Required]
public string Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string bc { get; set; }
}
Table looks something like this in SQL Server...
CREATE TABLE [dbo].[ColorSchemes](
[Id] [nvarchar](50) NOT NULL,
[Name] [varchar](32) NOT NULL,
[bc] [nchar](7) NOT NULL
)
I have added the table to the application context like such...
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<ColorSchemesViewModel> Colors { get; set; }
I have also used as separate class similarly like..
public DbSet<ColorSchemes> Colors { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
I have added the context to a controller like this...
private ApplicationDbContext _context;
public MyController(IMemoryCache memoryCache, ILoggerFactory loggerFactory, ApplicationDbContext context)
{
_memoryCache = memoryCache;
_logger = loggerFactory.CreateLogger<ChordMVCController>();
_context = context;
}
I have tried to query the table in my controller like this...
var colorSchemes = (from c in _context.Colors
select c).ToList();
I have attempted to use the Package Manager to per instructions from the error...
PM> Update-Database
I always get this error...
System.Data.SqlClient.SqlException: There is already an object named 'AspNetRoles' in the database.
This doesn't make sense since this table is already in the database and the EF definition. How do I get my table added properly to the EF migrations so I can query it?
I was able to solve this myself...
I created a different context rather than trying to embed the dbset in the default ApplicationDbContext and also removed the onModelCreating method.
public class ColorSchemeDbContext : DbContext
{
public ColorSchemeDbContext(DbContextOptions<ColorSchemeDbContext> options) : base(options)
{
}
public DbSet<ColorScheme> ColorSchemes { get; set; }
}
Replaced the ApplicationDBContext with the new context in my controller class...
private readonly ColorSchemeDbContext _context;
public MyController(IMemoryCache memoryCache, ILoggerFactory loggerFactory, ColorSchemeDbContext context)
{
_memoryCache = memoryCache;
_logger = loggerFactory.CreateLogger<ChordMVCController>();
_context = context;
}
After that the query worked. I spent a lot of time attempting to use the EF migrations to create the tables from a class syntax. Nothing seemed to work. I was creating a new .NET CORE web application in VS 2015 with the template and using user authentication which creates the AspNetRoles tables in SqlLite once you do an update-database. It is very confusing how to add additional tables using a code first approach after that. A lot more documentation is needed regarding EF migrations with respect to managing projects over time. I see the benefits of having all of your database updates maintained from your VS project but it is not easy to understand.

Schema not supported error in asp.net mvc web api

I am working on asp.net mvc 4 web api. I am using code first with existing database model. I have a single table in my database so i have the entity class like,
public class Tab1
{
[Key]
public int Field1{get; set;}
public string Field2{get; set;}
}
I have DBContext file like,
public class MyDBContext:DbContext
{
public DbSet<Tab1> Table{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Bar>().ToTable("bars");
}
}
and my Get Action is like
public List<Bar> GetTables()
{
MyDBContext context=new MyDBContext();
return context.Table.ToList();
}
But I am getting an error Schema specified is not valid error 0064: Facet 'MaxLength' must not be specified for type 'mediumtext'.. so please guide if i did any mistake in the process.
Here i have one more class like
public class Tab2:Tab1
{
public string Filed3{get; set;}
}
I dont want to create table in database with tab2 since i used tab2 class for returning custom records. I got the above error due to Tab2 inheriting from tab1 when i remove class tab2 it works as usual. so please guide me.
If you problem is only caused when introducing the "Tab2" class in the model and you don't really want "Tab2" to be stored in the database why don't you just annotate the "Tab2" class with the the [NotMapped] attribute or use the fluent configuration ModelBuilder.Ignore.

InverseProperty with Database Migration doesn't work when property is protected or internal

I have the following Entity Models
public class User
{
public virtual long Id{get; set;}
[InverseProperty("Users")]
public virtual ICollection<Tag> Tags { get; protected set; }
}
public class Tag
{
public virtual long Id{get; set;}
internal protected virtual ICollection<User> Users { get; set; }
}
This is pure simple many-to-many relation User & Tag
I'm using Data Migrations. When I execute the command Add-Migration or Update-Database
I get the following error "The InversePropertyAttribute on property 'Tags' on type 'Kigg.DomainObjects.Entities.User' is not valid. The property 'Users' is not a valid navigation property on the related type 'Kigg.DomainObjects.Entities.Tag'. Ensure that the property exists and is a valid reference or collection navigation property."
When I changed the access modifier of Users property in Tag to public it worked fine and the generation is what I want.
From my design point of view I want to hide the Tag.Users property and make it protected or internal to keep it for internal use as I don't want to expose it to public API.
Note: I'm not discussing the my design here. I'm asking if it's possible to do that while Tag.Users is protected or internal?
I don't know how to make it work with data annotations but with Fluent API you can apply and experiment with the trick from here: http://blog.cincura.net/232731-mapping-private-protected-properties-in-entity-framework-4-x-code-first/
For your model it would look like the following:
public class User
{
public virtual long Id{get; set;}
public virtual ICollection<Tag> Tags { get; protected set; }
}
public class Tag
{
public virtual long Id{get; set;}
internal protected virtual ICollection<User> Users { get; set; }
public class PropertyAccessors
{
public static readonly Expression<Func<Tag, ICollection<User>>> Users
= t => t.Users;
}
}
Mapping in FluentAPI:
modelBuilder.Entity<User>()
.HasMany(u => u.Tags)
.WithMany(Tag.PropertyAccessors.Users);
This works and creates the expected many-to-many relationship.
But I am not sure if you can do anything useful with that navigation property. The fact that you have the property protected and virtual lets me guess that you basically want lazy loading support inside of the entity class or derived classes.
The problem is that apparently (according to my tests at least) lazy loading doesn't work for anything else than a public property. The loaded tag is a proxy but the navigation collection is always null (unless the property is public).
Moreover, even eager and explicit loading don't work:
Outside of the Tag class:
// Eager loading
var tag = context.Tags.Include(Tag.PropertyAccessors.Users).First();
// Explicit loading
var tag2 = context.Tags.First();
context.Entry(tag2).Collection(Tag.PropertyAccessors.Users).Load();
Or inside of the Tag class (some method in Tag which gets the context passed):
public DoSomething(MyContext context)
{
// Eager loading
var tag = context.Tags.Include(t => t.Users).First();
// Explicit loading
context.Entry(this).Collection(t => t.Users).Load();
}
In all cases I get an exception that the property Users on entity Tag is not a valid navigation property. (The exception disappears as soon as I make the property public.)
I don't know if adding/removing/updating relationships would work. (I doubt.)
It looks that you can map a non-public navigation property with this approach to generate the expected database schema. But it seems that there is nothing useful you can do with it.
I don't know much about EF5 but you can use the attribute InternalsVisibleToAttribute to make internal members visible to a specific assembly.

Can the Entity Framework Code First generate properly for System.Drawing.Font or Dictionaries?

I am trying to generate a CMS using the Entity Framework Code First. I have a TextBox class that I'd like to have a System.Drawing.Font property or a Dictionary Property. Can the Entity Framework Code First generate properly for System.Drawing.Font or Dictionaries?
EF CF is a code-based ORM (Object-Relational Mapper). It handles the storage and retrieval of data held in classes in your app to and from tables in a database.
If you want to store/retrieve data from your forms, you should create "model" classes - these are just simple classes that contain properties for the values you want to store in your DB. For example:
public class Page
{
public Guid ID {get; set;}
public string Title {get; set;}
public string Body {get; set;}
public string FontName {get; set;}
public int FontSize {get; set;}
}
You then create a DbContext class that contains DbSet instances of the type of your model classes:
public class StorageContext : DbContext
{
public DbSet<Page> Pages {get; set;}
}
Now, EF will figure out the structure of the data you want to store and handle all the DB operations to load/store your data to your DB.
You should be able to write pretty much all your model and DB code (in a separate library in case you need to reuse).
Note: I also strongly encourage you to add an additional level of abstraction and create a Repository class so that your UI code needs know nothing about HOW you're storing your data - this will allow you to change to a completely different storage engine later without having to touch your app code! For example:
public class PageRepo
{
StorageContext _ctx = new StorageContext();
public Page GetPageById(Guid id)
{
...
}
public void StorePage(Page page)
{
...
}
}
You then use your StorageContext (or, better still, your repository) and Model classes to get/store data from/to your DB and copy those values into the necessary fields in your forms, peprforming any data validation before you store data, of course ;)
HTH.
Entity framework allows you to only map few predefined types. That is because it is an ORM and data types that are common to many RDBMS are supported. You can how ever break the complex type such as Font to its primitive properties and map to an entity.
Eg
public class Style
{
public Guid ID {get; set;}
public string FontName {get; set;}
public int FontSize {get; set;}
// other properties
}
In your UI layer you would have a TextBox that will use the style to build a Font.
public class TextBox
{
public TextBox(Style style)
{
Style = style;
}
protected Style Style {get; set;}
public Font FontSize { get { return new Font(Style.FontName, Style.FontSize); } }
// other properties
}