entity -> interface relationship, how to map - c#

I’m trying to develop some basic web app. I will post question with only two entities Article and Image.
One article has many images, and one or more images belong to only one article.
Every article implements interface IArticle and abstract class ArticleBase. ArticleBase defines only common properties for each article but child articles can have more properties beside those defined in ArticleBase.
So I have (IArticle, ArticleBase, ArticleComputer, ArticleCar)
public abstract class ArticleBase : Entity, IArticle
{
...
public string Name { get; set; }
public DateTime Created { get; set; }
}
public class ArticleComputer : ArticleBase
{
public virtual IList<Image> Images {get; set;}
public virtual OSTypeEnum OS {get; set;}
...
}
public class ArticleCar : ArticleBase
{
public IList<Image> Images {get;set;}
public virtual EngineTypeEnum EngineType {get; set;}
...
}
public class Image : Entity<Guid>
{
public virtual IArticle Article {get; set;}
}
So my question would be: how should I map Image object since I do not want to map every Article which implements IArticle independently?
public class ImageMap : ClassMapping<Image>{
public ImageMap() {
Id(x => x.Id, m => m.Generator(Generators.Identity));
ManyToOne(x => x.Article, m =>
{
m.NotNullable(true);
});
}
}

Why not create an interim abstract class
public abstract class ImageArticle : ArticleBase
{
public virtual IList<Image> Images { get; protected set; }
}
So ComputerArticle : ImageArticle, etc and Image becomes:
public class Image : Entity<Guid>
{
public virtual ImageArticle Article { get; set; }
}
And map: (I normally use Fluent NHibernate so apologies if this is the incorrect syntax)
public class ImageArticleMapping : SubclassMapping<ImageArticle>
{
public ImageArticleMapping()
{
this.Bag(x => x.Images)
}
}

Related

One to one or zero mapping in Entity Framework Core 2.2

I have a series of models that relate to a parent model, and the series of models have a child table that relates back to the original parent, so:
Public Class A
{
[Key]
public long AId {get; set;}
public string Name {get; set;}
}
Public Class B1
{
[Key]
public long Id {get; set;}
[ForeignKey("AId")]
public virtual A a {get;set;}
public virtual ICollection<C> Cs {get;set}
}
Public Class B2
{
[Key]
public long AId {get; set;}
[ForeignKey("AId")]
public virtual A a {get;set;}
public virtual ICollection<C> Cs {get;set}
}
Public Class C
{
public long CId {get; set;}
public long AId {get; set;}
[ForeignKey("AId")]
public virtual A a {get;set;}
}
The ApplicationDBContext ties the one to one/zero entities together with fluent api, but I can't figure out how to tie c. The context looks like this:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<A> As { get; set; }
public DbSet<B1> B1s { get; set; }
public DbSet<B2> B2s { get; set; }
public DbSet<C> Cs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<B1>().HasOne(x => x.a).WithOne().HasForeignKey<A>(p => p.Id);
}
I want to tie C in with something like this:
modelBuilder.Entity<B1>().HasMany(x => x.Cs).WithOne(y => y.a);
But it doesn't like this because it is referencing table A, the parent, which is what I want it to do. This is my first attempt at using Core and I am not finding a way to tie 3 tables together with fluent api. I was able to do this in EF 4.6, so I am assuming this should be possible in Core.
Any help would be appreciated.
I figured it out....
modelBuilder.Entity<B1>().HasMany(x => x.Cs).WithOne().HasForeignKey(y => y.AId);
Hopefully this helps someone else out.

Entity Framework Include Record with certain value in a Navigation Property

I am using Entity Framework 6 Code First and I'm configuring the mapping of my domain model with Fluent API. I don't see how to create a navigation properties for a Table which is a little tricky.
I have several objects which can make noise, I would like to record that noise in a NoiseRecord Table.
I need some kind of conditional mapping, something like that :
modelBuilder.Entity<NoiseRecord>().HasRequired(n=>n.Origine.OrigineType()=="Car").WithMany(c=>c.NoiseRecords);
That would be the mapping of the Car Navigation Property to avoid that, for example, it includes record related to Planes.
Here is my code
public interface INoisy
{
int ID {get; set;}
string OriginType()
...
//And other useful things not related to persistence
}
public class Car : INoisy
{
...
ICollection<NoiseRecord> NoiseRecords { get; set; }
string OrigineType()
{
return "Car";
}
}
public class Plane : INoisy
{
...
ICollection<NoiseRecord> NoiseRecords {get; set;}
string OrigineType()
{
return "Plane";
}
}
And a couple of other classes implement INoisy also.
Below is the NoiseRecord Table.
public class NoiseRecord
{
public int RecordID {get; set;}
public INoisy NoiseOrigine {get; set;}
public double NoiseMagnitude {get; set;}
}
I'm looking for a way to achieve that with Fluent API.
Thank you !
First of all, it is not possible to use interfaces as navigation properties. But you could use an abstract base class for your noise origins
public abstract class NoiseOrigin
{
public NoiseOrigin()
{
this.NoiseRecords = new Collection<NoiseRecord>();
}
public int Id { get; set; }
public ICollection<NoiseRecord> NoiseRecords { get; set; }
}
public class Car : NoiseOrigin {}
public class Plane : NoiseOrigin { }
public class NoiseRecord
{
public int Id { get; set; }
public int OriginId { get; set; }
public NoiseOrigin Origin { get; set; }
public double NoiseMagnitude { get; set; }
}
Your fluent API mapping whould look like this
public class NoiseModelContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Car>().Map(p => p.Requires("Type").HasValue("Car"));
modelBuilder.Entity<Plane>().Map(p => p.Requires("Type").HasValue("Plane"));
}
public DbSet<NoiseOrigin> NoiseOrigins { get; set; }
public DbSet<NoiseRecord> NoiseRecords { get; set; }
}
To get all car noise records your query will look like
using (var db = new NoiseModelContext()) {
var records = db.NoiseRecords.Where(p => p.Origin is Car);
// or like this - the result is the same.
var records2 = db.NoiseOrigins.OfType<Car>().SelectMany(p => p.NoiseRecords);
}

NotSupportedException: The type A cannot be mapped as definede. Table per Concrete (TPC) EF6

I have model like:
public abstract class Entity
{
public int Id { get; set; }
}
public abstract class Tree : Entity
{
public Tree() { Childs = new List<Tree>(); }
public int? ParentId { get; set; }
public string Name { get; set; }
[ForeignKey("ParentId")]
public ICollection<Tree> Childs { get; set; }
}
public abstract class Cat : Tree
{
public string ImageUrl { get; set; }
public string Description { get; set; }
public int OrderId { get; set; }
}
public class ItemCat : Cat
{
...
public virtual ICollection<Item> Items { get; set; }
}
and config classes:
public class CatConfig : EntityTypeConfiguration<Cat>
{
public CatConfig()
{
//properties
Property(rs => rs.Name).IsUnicode();
Property(rs => rs.ImageUrl).IsUnicode();
Property(rs => rs.Description).IsUnicode();
}
}
public class ItemCatConfig :EntityTypeConfiguration<ItemCat>
{
public ItemCatConfig()
{
Map(m => { m.ToTable("ItemCats"); m.MapInheritedProperties(); });
}
}
and DbContext:
public class Db : IdentityDbContext<MehaUser>
{
public Db():base("Db")
{
}
public DbSet<ItemCat> ItemCats { get; set; }
}
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Configurations.Add(new ItemCatConfig());
base.OnModelCreating(mb);
}
but get:
System.NotSupportedException: The type 'ItemCat' cannot be mapped as defined because it maps inherited properties from types that use entity splitting or another form of inheritance. Either choose a different inheritance mapping strategy so as to not map inherited properties, or change all types in the hierarchy to map inherited properties and to not use splitting
Update: I also Read this
Find the answer. just remove Map in ItemCatConfig Class.
Map(m => { m.ToTable("ItemCats"); m.MapInheritedProperties(); });
In TPC abstract classes does not implement in db.
ItemCat inherit from abstract classes and it doesn't need to Map configuration explicitly.

Fluent API EF 6 - How to configure 1:M (with M being of the same type)

I'm making my first steps with Fluent Api and I'm trying to understand how to do the following: This is my model.
public class Person
{
public int Id {get ; set;}
public List<View> Viewers {get; set;}
}
public class View
{
public int Id {get; set;}
public Person Viewer {get; set;}
}
This is a simplification of my model, I want to keep track of Person's that access some others profiles. I want to know for every person who has seen their profile.
I have tried this:
var view = modelBuilder.Entity<View>();
view.HasKey(v=>v.Id);
var person = modelBuilder.Entity<Person>();
person.HasKey(r => r.Id);
person.HasMany(t => t.Viewers).WithRequired(t=>t.Viewer);
I know this seems super silly, but from my code I want to be able to navigate:
Person -> Viewers (let's take viewer 1) -> Viewers, and so on...
Is this the right approach?
Thanks in advanced!
try this
public class Person
{ [Key]
public int Id { get; set; }
public ICollection<View> Viewers { get; set; }
}
public class View
{ [Key]
public int Id { get; set; }
public int ViewerId { get; set; } //this is a ForeingKey
public Person Viewer { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<View> Views { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<View>().HasRequired(a => a.Viewer).WithMany().HasForeignKey(a => a.ViewerId);
base.OnModelCreating(modelBuilder);
}
}
you may do the same with DataAnnotation Attributes and then it does't need to use Fluent API.
public class View
{
public int Id { get; set; }
public int ViewerId { get; set; }
[ForeignKey("ViewerId")] // here is a foreignkey property
[InverseProperty("Viewers")] // here is a navigation property in Person class
public Person Viewer { get; set; }
}

entity framework unidirectional association from one to many

I have an Account class which will be used to indicate who is responsible for a certain entity. There will be many entities where this will be used, so I don't want to pollute my Account class with all these collections
public class Account
{
public Guid Id{get; set;}
public Guid Name{get; set;}
...
public class EntityConfiguration : EntityConfigurationBase<Account>
{
public EntityConfiguration()
{
// I do not want these!
HasMany(a => a.As)
.WithOptional(x => x.Account)
.HasForeignKey(x =>x.AccountKey);
}
}
}
}
public class A
{
public Guid Id {get; set;}
public Account Account{get; set;}
// FK-Nav property
public Guid AccountKey{get;set;}
public class EntityConfiguration : EntityConfigurationBase<A>
{
public EntityConfiguration()
{
// what should go here to specify the association to Account?
????
}
}
}
public class B
{
public Guid Id {get; set;}
public Account Account{get; set;}
// FK-Nav property
public Guid AccountKey{get;set;}
public class EntityConfiguration : EntityConfigurationBase<B>
{
public EntityConfiguration()
{
// what should go here to specify the association to Account?
????
}
}
}
etc.
public class A
{
public Guid Id {get; set;}
public Account Account{get; set;}
// FK-Nav property
public Guid AccountKey{get;set;}
public class EntityConfiguration : EntityConfigurationBase<A>
{
public EntityConfiguration()
{
HasOptional(x => x.Account).HasMany().HasForeignKey(x=>x.AccountKey);
}
}
}

Categories

Resources