I want to use a FromSqlRaw query with view models and inheritance between them.
I created two example view models:
public class SummaryVM
{
public int Quantity { get; set; }
public int Value { get; set; }
}
public class DistrictVM : SummaryVM
{
public string DistrictName { get; set; }
}
My DbContext has this content:
public DbSet<SummaryVM> SummaryVMs { get; set; }
public DbSet<DistrictVM> DistrictVMs { get; set; }
...
modelBuilder.Entity<SummaryVM>().HasNoKey();
My query:
return await _context.DistritVMs.FromSqlRaw(query).ToListAsync();
but I get an error:
SqlException: Invalid column name 'Discriminator'. Invalid column name 'DistrictName'
I know this is due to the TPH pattern and I can solve this problem if I do not use inheritance yet how I can use these two tables with inheritance without TPH, please?
SOLUTION
I had to create a base class which is not registered as entity:
public abstract BaseClass
{
public int Quantity { get; set; }
public int Value { get; set; }
}
public class SummaryVM : BaseClass
{
}
public class DistrictVM : BaseClass
{
public string DistrictName { get; set; }
}
SOLUTION
I had to create a base class which is not registered as entity:
public abstract BaseClass
{
public int Quantity { get; set; }
public int Value { get; set; }
}
public class SummaryVM : BaseClass
{
}
public class DistrictVM : BaseClass
{
public string DistrictName { get; set; }
}
Related
Suppose I had these two classes:
public class MyClass {
public int Id { get; set; }
public IEnumerable<MyData> MyDataCollection { get; set; }
}
public class MyData {
public int DataId { get; set; }
public string Data { get; set; }
public int Id { get; set; }
}
and I had two tables in my database:
MyClasses:
Id
1
2
MyDatas:
DataId Id Data
1 - 1 - "Hello"
2 - 1 - "World"
3 - 2 - "Hello World"
How do I use entity framework to link them up, so that I can do:
using (var db = new DataContext()) {
var data = db.MyClass.Where(c => c.ID == 1).MyDataCollection;
foreach (var item in data) Console.WriteLine(item.Data);
}
I have the other data but so far I've just written [NotMapped] above the MyDataCollection property, but obviously I want to get rid of that and have it mapped. How do I (correctly) map it?
You can do it by expanding your class with appropriate navigation properties to establish the joins between them by following EF standards
public class MyClass {
public MyClass()
{
MyDataCollection = new List<MyData>();
}
public int Id { get; set; }
public virtual ICollection<MyData> MyDataCollection { get; set; }
}
public class MyData {
public int DataId { get; set; }
public string Data { get; set; }
public int Id { get; set; }
public virtual MyClass MyClass { get; set; }
}
Make sure these 2 entities are declared in the dbcontext as below
public class MyContext: DbContext
{
public MyContext(): base()
{
}
public DbSet<MyClass> MyClasses { get; set; }
public DbSet<MyData> MyDatas { get; set; }
}
Why am I getting this error when executing?
dnx ef database update
The property 'RowValues' on entity type 'Models.Foo' has not been added to the model or ignored.
public class Foo
{
public ICollection<int> RowValues { get; set; }
public ICollection<int> ColValues { get; set; }
}
The EDM does not support collections of primitive data types
Source
You have to do something like:
public class Value
{
public int Id { get; set; }
public int Value { get; set; }
}
public class Foo
{
public int Id { get; set; }
public ICollection<Value> RowValues { get; set; }
public ICollection<Value> ColValues { get; set; }
}
(Don't forget the ID property...)
In the MSDN they show how to implement EF TPT with this example:
public abstract class BillingDetail
{
public int BillingDetailId { get; set; }
public string Owner { get; set; }
public string Number { get; set; }
}
[Table("BankAccounts")]
public class BankAccount : BillingDetail
{
public string BankName { get; set; }
public string Swift { get; set; }
}
[Table("CreditCards")]
public class CreditCard : BillingDetail
{
public int CardType { get; set; }
public string ExpiryMonth { get; set; }
public string ExpiryYear { get; set; }
}
public class InheritanceMappingContext : DbContext
{
public DbSet<BillingDetail> BillingDetails { get; set; }
}
Regarding (*) I have this question:
Can I have a DbSet per child in the hierarchy? ie:
public class InheritanceMappingContext : DbContext
{
public DbSet<BankAccount> BankAccount { get; set; }
public DbSet<CreditCard> CreditCards{ get; set; }
}
I'm asking this because I'd like to have a main father class from which all the other classes inherit, ie:
public abstract class DatabaseItem
{
[Key]
public long DatabaseItemId { get; set; }
}
public User : DatabaseItem
{
...
}
public Picture : DatabaseItem
{
...
}
public Gallery : DatabaseItem
{
...
}
So that given an ID, I know that it corresponds to only one thing.
In the past in other projects I didnt do this, and used specifical IDs: "UserId", "PictureId", "GalleryId".
In this case, I will be having only one DbSet?
DbSet<DatabaseItem> DatabaseItems
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 such relations:
class FirstParent {
public SecondParent SecondRecord { get; set; }
}
class SecondParent {
public IEnumerable<FirstParent> FirstRecords { get; set; }
}
class FirstChild1 : FirstParent {
public String StrInFirstChild1{ get; set; }
}
class SecondChild1 : SecondParent {
public String StrInSecondChild1{ get; set; }
}
class FirstChild2 : FirstParent {
public String StrInFirstChild2{ get; set; }
}
class SecondChild2 : SecondParent {
public String StrInSecondChild2{ get; set; }
}
Records related to class FirstChild1 are of type SecondChild1.
Records related to class FirstChild2 are of type SecondChild2.
When I write
var record = from ch in context.FirstParent.OfType<FirstChild1>() select ch.SecondRecord;
in result I also have SecondParent object.
What is happening? How to load SecondChild1 objects?
I found a resolution. I load records from all four tables and do join to collect needed information to anonymous object.