Oracle ODP.Net and EF CodeFirst - edm.decimal error - entity-framework

I have the following simple entity:
public class Something{
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int ID { get; set; }
public string NAME { get; set; }
public int STATUS { get; set; }
}
As you can see, I do not want the ID is generated from the database but I'm going to enter manually. This my DbContext class:
public class MyCEContext : DbContext {
...
public DbSet<Something> Somethings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
string dbsch = "myce";
modelBuilder.Entity<Something>().ToTable("SOMETHING", dbsch);
}
}
There is nothing special here. But this code fails:
using (MyCEContext ctx = new MyCEContext()) {
Something t = new Something();
t.ID= 1;
t.NAME = "TEST";
t.STATUS = 100;
ctx.Somethings.Add(t);
ctx.SaveChanges();
}
This is the error:
The specified value is not an instance of type 'Edm.Decimal'
In general, allways EF try to send a value to an int primary key field, I get the edm.decimal error.
Any help?

As I commented on previous answer, I've found better solution, it is strange, but it works
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TestEntity>().ToTable("TESTENTITY", "SCHEMENAME");
modelBuilder.Entity<TestEntity>().Property(p => p.Id).HasColumnName("ID").HasColumnType("INT");
modelBuilder.Entity<TestEntity>().Property(p => p.TestDateTime).HasColumnName("TESTDATETIME");
modelBuilder.Entity<TestEntity>().Property(p => p.TestFloat).HasColumnName("TESTFLOAT");
modelBuilder.Entity<TestEntity>().Property(p => p.TestInt).HasColumnName("TESTINT");
modelBuilder.Entity<TestEntity>().Property(p => p.TestString).HasColumnName("TESTSTRING");
}
and TestEntity looks like this
public class TestEntity
{
public int Id{ get; set; }
public string TestString { get; set; }
public int TestInt { get; set; }
public float TestFloat { get; set; }
public DateTime TestDateTime { get; set; }
}

Related

Including a Model from different DbContext

I am not sure how to achieve the relation between 2 DbContexts. PurchaseOrderDbContext is a Code first approach & AgencyDbContext is an existing database. How can I include the "Division" from AgencyDbContext based on PurchaseOrder DivisionId?
To start off here is a very simplified version of my code.
Purchase Order Model
namespace Website.Models.PurchaseOrders
{
public class PurchaseOrder
{
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public string Name { get; set; }
public int DivisionId { get; set; }
public int StatusID { get; set; }
public Agency.Division Division { get; set; }
}
}
Division Model (this is in a different DbContext)
namespace Website.Models.Agency
{
public class Division
{
public int DivisionId { get; set; }
public string DivisionName { get; set; }
public string DivisionShortName { get; set; }
public string DivisionAbbrev { get; set; }
public int? DivisionDirectorEmpId { get; set; }
}
}
Agency DbContext
namespace Website.Models.Agency
{
public class AgencyDbContext : DbContext
{
public Agency DbContext(DbContextOptions<AgencyDbContext> options) : base(options)
{
}
public virtual DbSet<Division> Division { get; set; }
public virtual DbSet<Section> Section { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}
PurchaseOrderDbContext
namespace Website.Models.PurchaseOrders
{
public class PurchaseOrderDbContext : DbContext
{
public PurchaseOrderDbContext(DbContextOptions<PurchaseOrderDbContext> options) : base(options)
{}
public DbSet<Status> Statuses { get; set; }
public DbSet<PurchaseOrder> PurchaseOrder { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}
I get an the error InvalidOperationException: Lambda expression used inside Include is not valid. This is referring to the Include extension on Division.
var purchaseOrder = _context.PurchaseOrder
.Include(p => p.Division)
.Include(p => p.Status)
.OrderByDescending(p => p.OrderDate);
Thank you in advance!
Probably the only way to resolve is to make a query to the first context for items you are looking for, and then populate Division property with entries from second context
public class PurchaseOrderService
{
private readonly PurchaseOrderDbContext purchaseOrderDbContext;
private readonly AgencyDbContext agencyDbContext;
public PurchaseOrderService(PurchaseOrderDbContext purchaseOrderDbContext,
AgencyDbContext agencyDbContext)
{
this.purchaseOrderDbContext = purchaseOrderDbContext;
this.agencyDbContext = agencyDbContext;
}
public PurchaseOrder Get(int id)
{
var purchaseOrder = purchaseOrderDbContext.PurchaseOrder.FirstOrDefault(x => x.ID == id);
if (purchaseOrder == null)
{
return null;
}
purchaseOrder.Division = agencyDbContext.Division.FirstOrDefault(x => x.DivisionId == purchaseOrder.DivisionId);
return purchaseOrder;
}
}

Can we mix new table and existing view in EF code first

I created some classes and a table in db for those classes with migration. I tested my code by adding some data to the classes,saved by EF and saw the data saved properly in db.
Later when I created a view in db and maped that view in code the problems started. When I tried to query this way:
using (var db = new TestDBContext())
{
var listMyViews = db.vwCustomer.ToList();
}
I was getting an error message like
Additional information: The model backing the 'TestDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database
So EF is telling me to migrate features to create view in db but view exists already. So why do I need to recreate it by migration?
my full code with view mapping and class
public class CustomerBase
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
}
public class Customer : CustomerBase
{
public virtual List<Addresses> Addresses { get; set; }
}
public class Addresses
{
[Key]
public int AddressID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public bool IsDefault { get; set; }
public virtual List<Contacts> Contacts { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
public class Contacts
{
[Key]
public int ContactID { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public bool IsDefault { get; set; }
public int AddressID { get; set; }
public virtual Addresses Customer { get; set; }
}
public class vwCustomer
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
}
public class TestDBContext : DbContext
{
public TestDBContext()
: base("name=TestDBContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new vwCustomerConfiguration());
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Addresses> Addresses { get; set; }
public DbSet<Contacts> Contacts { get; set; }
public DbSet<vwCustomer> vwCustomer { get; set; }
}
public class vwCustomerConfiguration : EntityTypeConfiguration<vwCustomer>
{
public vwCustomerConfiguration()
{
this.HasKey(t => t.CustomerID);
this.ToTable("vwCustomer");
}
}
Later I tried to see if any migration is pending issuing Add-Migration "My_vwCustomer". I saw new migration code being added as below. It seems there is no migration pending.
public partial class My_vwCustomer : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.vwCustomers",
c => new
{
CustomerID = c.Int(nullable: false, identity: true),
FirstName = c.String(),
})
.PrimaryKey(t => t.CustomerID);
}
public override void Down()
{
DropTable("dbo.vwCustomers");
}
}
Another way we can do it and it solve my problem. see the code.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<YourDbContext>(null);
base.OnModelCreating(modelBuilder);
}
code taken from here https://stackoverflow.com/a/6143116/6188148
we can follow this approach too.
public partial class AddingvwCustomer : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
i guess this will works too but not tested myself.
we can use the Fluent API to configure it using the Ignore method:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<MyClass>();
}
thanks

EF one-to-one relation not creates

I'll try create one-to-one relation using EF and Fluent API.
First class:
public class Game
{
public int Id { get; set; }
public Guid Token { get; set; }
public string Player { get; set; }
public virtual Field Field { get; set; }
public virtual ICollection<Move> Moves { get; set; }
public GameStatus Status { get; set; }
public DateTime StartTime { get; set; }
public DateTime? EndTime { get; set; }
public PlayerCode Winner { get; set; }
public Game()
{
Status = GameStatus.NoteDone;
StartTime = DateTime.UtcNow;
Winner = PlayerCode.None;
Field = new Field {Game = this};
Token = Guid.NewGuid();
}
}
Secong class:
public class Field : IEntity
{
public int Id { get; set; }
public virtual Game Game { get; set; }
public string CellsString { get; set; }
}
And configure relations in context
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Game>()
.HasRequired<Field>(g => g.Field)
.WithRequiredDependent(f => f.Game);
base.OnModelCreating(modelBuilder);
}
But after this relation in DB is not created. Tables look like this
I try many variations of Fluent configuration, but no one works for me. Where i do mistake?
You can specify a mapping for foreign key if you don't wish to add it as a property to your entity class.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Game>()
.HasRequired(g => g.Field)
.WithRequiredPrincipal(f => f.Game)
.Map(m => m.MapKey("GameId"));
}
You probably meant WithRequiredPrincipal, not WithRequiredDependent since you probably want that foreign key to be in the Field table.

Fluent Mapping gone wrong on EF 4.1 with Code First

Here a simple model:
public class Product1
{
public int Id { get; set; }
public double Price { get; set; }
public int CurrencyID { get; set; }
public Currency Currency { get; set; }
}
public class Product2
{
public int Id { get; set; }
public double Price { get; set; }
public int CurrencyID { get; set; }
public Currency Currency { get; set; }
}
public class Currency
{
public int Id { get; set; }
public string Name { get; set; }
public string ISO4217 { get; set; }
public string Symbol { get; set; }
}
As you can see, Currency is just a list that will be used by two different entities, but If I try to run this, it gives me an error saying that this is not valid as could lead to multiple cascade paths.
Now I'm trying to figure how to model this on OnModelCreating
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product1>().HasRequired(p => p.Currency).WithMany().WillCascadeOnDelete(false);
modelBuilder.Entity<Product2>().HasRequired(p => p.Currency).WithMany().WillCascadeOnDelete(false);
}
But for some reason, although the product is correctly created, whenever I try to load it, Currency comes null.
What am I doing something wrong in this modelling?
Thanks!
I figured it out and I will explain here for future reference: After better looking the base created, I realized that it was creating a FK for the wrong field: P1:ID -> Currency:ID, when the correct should be P1:CurrencyID -> Currency:ID
So I found a way to force the correct FK:
modelBuilder.Entity<Product1>().HasRequired(p => p.Currency).WithMany().HasForeignKey(p => p.CurrencyId);
And that's all!
Map you classes like this:
public class Product1Mapping : EntityTypeConfiguration<Product1>
{
public Product1Mapping ()
{
ToTable("Product1");
HasKey(p => p.Id);
HasRequired(p => p.Tag).WithMany().HasForeignKey(t => t.CurrencyID);
}
}
public class Product2Mapping : EntityTypeConfiguration<Product2>
{
public Product2Mapping ()
{
ToTable("Product2");
HasKey(p => p.Id);
HasRequired(p => p.Tag).WithMany().HasForeignKey(t => t.CurrencyID);
//other properties
}
}
and change you OnModelCreating creating method like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new AccountMapping());
// Add other mapping classes
}
public DbSet<Product1> Product1{ get; set; }
public DbSet<Product2> Product2{ get; set; }
see these links for more information:
http://msdn.microsoft.com/en-us/data/jj591617.aspx
http://entityframework.codeplex.com/workitem/1049

Why can't I do ToList()?

I build a model as below. The relationship between Recycler and Account is 1:1.
public class MyContext : DbContext
{
public DbSet<Quoter> Quoters { get; set; }
public DbSet<Account> Accounts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>()
.HasRequired(a => a.RecyclerRef)
.WithRequiredDependent(r => r.AccountRef);
}
}
public class Quoter
{
public int QuoterId { get; set; }
public string Text { get; set; }
}
public class Recycler : Quoter
{
public string Description { get; set; }
public virtual Account AccountRef { get; set; }
}
public class Account
{
public int AccountId { get; set; }
public Recycler RecyclerRef { get; set; }
}
But, I get exceptions when I do the either of these queries:
var query1 = context.Quoters
.OfType<Recycler>()
.Include(r => r.AccountRef)
.Where(r => r.QuoterId == 1)
.ToList();
var query2 = context.Set<Recycler>()
.Include(r => r.AccountRef)
.Where(r => r.QuoterId == 1)
.ToList();
Exception shows that ResultType is “Transient.reference[POCOFirst.Quoter]”,but recommanded is “Transient.reference[POCOFirst.Recycler]”
If I remove the ToList(), it works well. But I need a list as the return value of method.
Why can't I do ToList()? Thanks
It looks like you have stumble upon this bug in EF. Another reference to the bug.
Workaround would be to remove the Include method.