I have the following (abbreviated) DbContext:
public class O19Context : BaseContext<O19Context>
{
public DbSet<PRJ> O19Set { get; set; }
}
[Table("AUFK")]
public class AUFK
{
[ForeignKey("PRJ_GUID")]
public PRJ PRJ {get; set;}
[Key]
public Guid AUFK_GUID {get; set;}
}
[Table("PRJ")]
public class PRJ
{
[Key]
public Guid PRJ_GUID {get; set;}
public IQueryable<AUFK> AUFKS {get; set;}
}
When I run the following code:
var db = new O19Context();
var prj = db.O19Set.Include("AUFKS")
.Single(o => o.PRJ_GUID ==
new Guid("6FE5E97B-9970-4E24-B051-9A710C03A030"));
I get an invalid Include path error. The EntityType PRJ does not declare a navigation property with the name AUFKS.
Where am I going wrong?
Pamela
A good way to see if EF likes your POCO is the EF Power Tools "View Entity Data Model (Read Only)".
http://www.infoq.com/news/2013/10/ef-power-tools-beta4
I made two changes to your code and it now creates a little diagram...
[TestClass]
public class O19Tests
{
[TestMethod]
public void O19Test1()
{
var db = new O19Context();
var prj = db.O19Set.Include("AUFKS")
.FirstOrDefault(o => o.PRJ_GUID ==
new Guid("6FE5E97B-9970-4E24-B051-9A710C03A030"));
}
}
public class O19Context : DbContext//<O19Context>
{
public DbSet<PRJ> O19Set { get; set; }
}
[Table("AUFK")]
public class AUFK
{
//[ForeignKey("PRJ_GUID")] //remove this...
//there is no PRJ_GUID field IN THIS CLASS
public PRJ PRJ { get; set; }
[Key]
public Guid AUFK_GUID { get; set; }
}
[Table("PRJ")]
public class PRJ
{
[Key]
public Guid PRJ_GUID { get; set; }
public IList<AUFK> AUFKS { get; set; } //use IList
}
A navigation property must implement ICollection<T> - you define the property as IQueryable<T> which I do not believe is supported
Related
I have SQLite db and these EF models and context.
Models and Context
public class CardHolder
{
public int CardHolderId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
public string EmailAddress { get; set; }
public string TenantName { get; set; }
public ICollection<AccessCard> AccessCards { get; set; }
}
public class AccessCard
{
public int AccessCardId { get; protected set; }
public CardHolder CardHolder { get; set; }
public DateTime ActivationDate { get; protected set; }
public bool ActivationProcessed { get; set; }
public DateTime? DeactivationDate { get; protected set; }
public string DeactivationReason { get; set; }
public bool DeactivationProcessed { get; set; }
}
public class MyContext : DbContext
{
public DbSet<CardHolder> CardHolders { get; set; }
public DbSet<AccessCard> AccessCards { get; set; }
}
And the Main program
class Program
{
static void Main(string[] args)
{
using (var db = new MyContext())
{
var cardHolders = db.CardHolders.Include("AccessCard").ToList();
}
}
}
Question1: Why do I get this exception
System.InvalidOperationException: 'A specified Include path is not
valid. The EntityType 'SQLiteDemo.Models.CardHolder' does not declare
a navigation property with the name 'AccessCard'.'
If I replace it with
var cardHolders = db.CardHolders.Include("AccessCards").ToList();
I get another error:
SQL logic error no such column: Extent2.CardHolder_CardHolderId
What is wrong with Entity Framework?
Question2: Why cant I use arrow function in Include statement, it doesnt compile at all?
var cardHolders = db.CardHolders.Include(x => x.AccessCards).ToList();
Question3: Why do I need to use Include at all if my ICollection association property AccessCards is NOT virtual - that means eager loading must work by itself!
Why the hell it is so problematic and buggy? Nothing works as it should :(
1 - You have a typo as you have already determined :)
1B - "SQL logic error no such column: Extent2.CardHolder_CardHolderId"
EF isn't finding your FK. You could add it to your AccessCard model:
public int CardHolderId { get; set; }
2 - You need to pull in the LINQ extensions. Make sure you have both of these using statements at the top:
using System.Data.Entity;
using System.Linq;
3 - You, like many others, are misunderstanding lazy loading. Eager loading still requires an Include() to fetch related data. Lazy loading only fetches the relations when you access them.
I understand the following code creates "One-to-One relationship" between a principal and a dependent entity.
However, I would like to ask:
Is it possible to create one-to-one relationship without including navigation property in the dependent entity?
If yes, than how should I re-write the following code?
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[Key, ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
To create a one-to-one relationship without a navigation property on the dependent side, you'll need to use the fluent API. For example, in your DbContext class, you can override OnModelCreating and use this to define the relationship:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// I'm assuming the report is optional
modelBuilder.Entity<Student>()
.HasOptional(t => t.StudentReport)
.WithRequired();
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
}
See documentation for WithRequired() here
I am using Entity Framework 6 with Generic Repository and DTOs.
I want to create new entities via navigation property.
Here is my model:
public partial class Project
{
public Project()
{
this.ProjectAssets = new List<ProjectAsset>();
}
public int ProjectID { get; set; }
public string Name { get; set; }
public virtual ICollection<ProjectAsset> ProjectAssets { get; set; }
}
public partial class Asset
{
public Asset()
{
this.Revisions = new List<Revision>();
}
public int AssetID { get; set; }
public string Name { get; set; }
public short Type { get; set; }
public virtual ICollection<Revision> Revisions { get; set; }
}
public partial class ProjectAsset
{
public int MappingID { get; set; }
public int ProjectID { get; set; }
public int AssetID { get; set; }
public virtual Asset Asset { get; set; }
}
I have already created Project. And if i am creating new Asset, then create Project Asset with AssetID from just created Asset, it's OK, but i have to re-fetch Project from DB.
I want to do it in one transaction, like that:
Project.ProjectAssets.Add(new ProjectAsset(new Asset((short)type, fileName)));
ServiceLocator.Default.ResolveType<IPipeLine>().Update(Project);
public void Update<TEntity>(TEntity entity) where TEntity : class
{
var fqen = GetEntityName<TEntity>();
object originalItem;
var key = ((IObjectContextAdapter)DbContext).ObjectContext.CreateEntityKey(fqen, entity);
if (((IObjectContextAdapter)DbContext).ObjectContext.TryGetObjectByKey(key, out originalItem))
((IObjectContextAdapter)DbContext).ObjectContext.ApplyCurrentValues(key.EntitySetName, entity);
//DbContext.Entry(entity).State = EntityState.Modified;
}
But after SaveChanges there is no record in DB, and MappingID still 0.
I thought that ApplyCurrentValues must work with Navigation Properties.
Is there any good way to solve that problem?
EDIT:
I accessing DAL throughBusiness Entities with contain the same properties, but they also implement INotifyPropertyChanged and other WPF stuff. So i think i can subscribe to CollectionChanged event and manualy create/delete entities from navigation property. And in property setters i can call update, but i think it can strongly decrease perfomance.
i am setting up the ef code first with table per type. See the following structure. The idea is to store inherited class information in its own table and at the same time a derived class can have reference to a parent and a list of children that also derive from the BaseClass.
public class BaseClass
{
public long Id {get;set;}
public string EntityType { get; set; }
}
public class A_Class : BaseClass
{
public string A_Property {get;set;}
public BaseClass Parent {get; set;}
public IList<BaseClass> Children { get; set; }
}
public class B_Class : BaseClass
{
public string B_Property {get;set;}
public BaseClass Parent {get; set;}
public IList<BaseClass> Children { get; set; }
}
Any idea how to setup the DbContext for the model?
To generate the 3 tables you can use the API:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BaseClass>().ToTable("BaseClass");
modelBuilder.Entity<A_Class>().ToTable("AClass");
modelBuilder.Entity<B_Class>().ToTable("BClass");
base.OnModelCreating(modelBuilder);
}
or the TableAttribute:
[Table("BaseClass")]
public class BaseClass
{
public int Id { get; set; }
public string EntityType { get; set; }
}
[Table("AClass")]
public class A_Class : BaseClass
{
public string A_Property { get; set; }
public BaseClass Parent { get; set; }
public ICollection<BaseClass> Children { get; set; }
}
[Table("BClass")]
public class B_Class : BaseClass
{
public string B_Property { get; set; }
public BaseClass Parent { get; set; }
public ICollection<BaseClass> Children { get; set; }
}
I have a shared type that I'd like to represent in a database. I need to know either if it's possible with code first or if it's bad design. (Please point to sources of your reasoning).
Here's the layout:
public class A
{
public Guid Id;
public Guid ParentId; // Points to either B or C
public string Foo;
}
public class B
{
public Guid Id;
public virtual ICollection<A> ManyA { get; set; }
// Other fields
}
public class C
{
public Guid Id;
public virtual ICollection<A> ManyA { get; set; }
// Other fields
}
I've managed GUID PKs by using the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] annotation, which I believe would make this possible.
The goal is to keep the A-table simple; I'd like it not to have B_Id and C_Id columns, as I think they're unnecessary, and there may be a D type in the future that has many A just like B and C. Also, this scenario is used for a few other relationships.
I think the spirit of the problem is apparent, however the EF-specific class members are just there for illustration. If they need changing, so be it.
(I'm sorry for the contrived example, however exposing the true nature of this, IMO, doesn't clarify the problem).
Also, I tried searching for hours! I don't know the proper nomenclature to find a suitable answer. I'm pretty new to databases and EF in general.
Don't use Guid to make a index, why you choose the hard-way ? :S
use the DataAnnotations like the example:
A class:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Web.Mvc;
namespace app.Models
{
[Table("A")]
public class A
{
[Key]
public int AId { get; set; }
[Required(ErrorMessage = "Campo obrigatório")]
[DisplayName("Title")]
[StringLength(100)]
public string Title { get; set; }
public virtual ICollection<B> bCollection { get; set; }
}
}
B class:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Web.Mvc;
namespace app.Models
{
[Table("B")]
public class B
{
[ScaffoldColumn(false)]
[Key]
public int BId { get; set; }
[DisplayName("Description")]
[StringLength(100)]
public string Description { get; set; }
public virtual ICollection<A> AList{ get; set; }
}
}
You can see more details here: link!!!
For more details about EF5 Data Annotations: link
I've found that I can make a common base type for both B and C types. For example:
class Program
{
static void Main(string[] args)
{
using (var context = new Ctx())
{
var b = new B();
var c = new C();
b.ManyA.Add(new A());
c.ManyA.Add(new A());
context.Cs.Add(c);
context.Bs.Add(b);
context.SaveChanges();
}
}
}
public class Ctx : DbContext
{
public DbSet<A> As { get; set; }
public DbSet<B> Bs { get; set; }
public DbSet<C> Cs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BaseClass>()
.HasMany<A>(b => b.ManyA)
.WithRequired(a => a.BaseObject)
.WillCascadeOnDelete(true);
}
}
public class BaseClass
{
public BaseClass() { ManyA = new HashSet<A>(); }
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual ICollection<A> ManyA { get; set; }
}
public class A
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public BaseClass BaseObject { get; set; }
public string Foo { get; set; }
}
public class B : BaseClass
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string SomeProperty { get; set; }
}
public class C : BaseClass
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public int SomeOtherProperty { get; set; }
}
And, based on this Msdn article, would result in Table Per Hierarchy database layout. TPH performs better versus TPT, which I was thinking could be an answer.
I was really hoping for something simpler, but performance is the bottom line, afterall