TPC doesnt work in CodeFirst-Migration - entity-framework

I have below class :
public abstract class BaseAttachment
{
public Guid BaseAttachmentId { get; set; }
public string FileName { get; set; }
public string FileExtension { get; set; }
public string FileSize { get; set; }
public Folder Folder { get; set; }
public Guid? FolderId { get; set; }
public byte[] RowVersion { get; set; }
}
And I have below Table and Inherite BaseAttachment :
public class ProductGallery : BaseAttachment
{
public ProductHeader ProductHeader { get; set; }
public Guid? ProductHeaderId { get; set; }
}
and this :
public class Attachment:BaseAttachment
{
}
when Run Project and Create Database I have Below Tables :
BaseAttachment,ProductCategory
instead Of One Table (BaseAttachment) .
why ?

I was a config Class Like this for ProductCategoryConfig and Set TableName with below :
public class ProductGalleryConfig:EntityTypeConfiguration<ProductGallery>
{
public ProductGalleryConfig()
{
ToTable("ProductGallery");
Property(row => row.Code).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(row => row.RowVersion).IsRowVersion();
HasRequired(row => row.ProductHeader).WithMany(row => row.Galleries).HasForeignKey(row => row.ProductHeaderId).WillCascadeOnDelete(false);
}
}
and Comment below Line and its fix.
// ToTable("ProductGallery");

Related

EF Core 7 - error occurred: the entity type 'List<string>' requires a primary key to be defined

I get an error when I use EF Core 7 to create entities.
The entity type 'List' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
I have found the error prop, that's Project of service entity, when I only annotate Project of service entity, then I can run Add-Migration successfully. I don't know why and I also don't know how to fix this error.
Does somebody know this error? Please help...
public class Service : EntityBase
{
public Guid? DefaultCapacityUnitId { get; set; }
public Guid? DefaultSizeUnitId { get; set; }
public virtual SizeUnit DefaultSizeUnit { get; set; }
public Guid ProjectId { get; set; }
public Project Project { get; set; }
public Guid? ParentId { get; set; }
public virtual Service Parent { get; set; }
public Guid DisciplineId { get; set; }
public virtual Discipline Discipline { get; set; }
public virtual List<Service> SubServices { get; set; } = new List<Service>();
}
public class Equipment : EntityBase
{
public Guid ProjectId { get; set; }
public Project Project { get; set; }
public Guid? ServiceId { get; set; }
public virtual Service Service { get; set; }
public Guid DisciplineId { get; set; }
public virtual Discipline Discipline { get; set; }
}
public abstract class EntityBase
{
[Key]
public virtual Guid Id { get; set; } = Guid.NewGuid();
private string name;
[Required, MaxLength(200)]
public virtual string Name
{
get
{
return name?.Trim();
}
set
{
name = value?.Trim();
}
}
private string shortName;
[Required, MaxLength(100)]
public virtual string ShortName
{
get
{
return shortName?.Trim();
}
set
{
shortName = value?.Trim();
}
}
[NotMapped]
public EntityBase Snapshot { get; set; }
[NotMapped]
public List<string> ValueChangedProperties { get; set; } = new List<string>();
}
public class Project : EntityBase
{
}
public class Discipline : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public virtual List<Service> Services { get; set; } = new List<Service>();
public Guid? ScenarioId { get; set; }
public Guid? ParentId { get; set; }
public virtual Discipline Parent { get; set; }
}
public partial class TestDbContext : DbContext
{
public TestDbContext(DbContextOptions<TestDbContext> options)
: base(options)
{ }
public TestDbContext()
{
}
public DbSet<Project> Projects { get; set; }
public DbSet<Discipline> Disciplines { get; set; }
public DbSet<Service> Services { get; set; }
public DbSet<ServiceGroup> ServiceGroups { get; set; }
public DbSet<SizeUnit> SizeUnits { get; set; }
public DbSet<Equipment> Equipments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var entityTypes = typeof(TestDbContext).GetProperties()
.Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
.Select(p => p.PropertyType.GetGenericArguments()[0]).ToList();
entityTypes.ForEach(entityType => {
var entityName = entityType.Name;
modelBuilder.Entity(entityType).ToTable(entityName);
});
modelBuilder.Entity<ServiceMapping>().HasOne(x => x.Service).WithMany().HasForeignKey(x => x.ServiceId).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ServiceMapping>().HasOne(x => x.TargetService).WithMany().HasForeignKey(x => x.TargetServiceId).OnDelete(DeleteBehavior.Cascade);
base.OnModelCreating(modelBuilder);
}
}
public class ServiceGroup : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public Guid? ScenarioId { get; set; }
}
public class ServiceMapping : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public Guid ServiceId { get; set; }
public virtual Service Service { get; set; }
public Guid TargetServiceId { get; set; }
public virtual Service TargetService { get; set; }
}
public class SizeUnit : EntityBase
{
public Guid ProjectId { get; set; }
public virtual Project Project { get; set; }
public int UnitType { get; set; }
}
If I annotate Project of service entity, then it's all right.

Entity Framework get all data from table with foreign key

Please help. I can not resolve the issue - the category name is null.
Thanks a lot.
The models
public class Product
{
[Key]
public int ProductID { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public int CategoryID { get; set; }
[ForeignKey("CategoryID")]
public virtual Category Category { get; set; }
}
public class Category
{
[Key]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
`
Product Controller
public async Task<IEnumerable<ProductDto>> GetProductsAsync()
{
List<Product> products = await _db.Products
.Include(u => u.Category)
.ToListAsync();
return _mapper.Map<List<ProductDto>>(products);
}
public class MappingProfiles : Profile
{
public MappingProfiles()
{
CreateMap<ProductDto, Product>().ReverseMap();
}
}
public class ProductDto
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public string CategoryName { get; set; }
}
How to resolve null fields?
Change your MappingProfiles like below:
public class MappingProfiles : Profile
{
public MappingProfiles()
{
CreateMap<Product, ProductDto>()
.ForMember(d => d.CategoryName, a => a.MapFrom(s => s.Category.CategoryName))
.ReverseMap()
.ForPath(b => b.Category, o => o.MapFrom(dto => (Category)null));
}
}

Entity Framework how to map composite entities?

I'm newbie in EF and i have such question:
I have four Entities, which describe the elements of the address:
public partial class Region : BaseEntity
{
private ICollection<RegionCity> _regionCities;
public string Code { get; set; }
public string Name { get; set; }
public int Timezone { get; set; }
public virtual ICollection<RegionCity> RegionCities
{
get
{
return _regionCities ?? (_regionCities = new List<RegionCity>());
}
protected set { _regionCities = value; }
}
}
public partial class RegionCity : BaseEntity
{
private ICollection<CityStreet> _cityStreets;
public int RegionId { get; set; }
public string CityName { get; set; }
public virtual Region Region { get; set; }
public virtual ICollection<CityStreet> CityStreets
{
get { return _cityStreets ?? (_cityStreets = new List<CityStreet>()); }
protected set { _cityStreets = value; }
}
}
public partial class CityStreet : BaseEntity
{
public int CityId { get; set; }
public string StreetName { get; set; }
public virtual RegionCity City { get; set; }
}
public partial class FullAddress : BaseEntity
{
public int CityStreetId { get; set; }
public string HouseNum { get; set; }
public string OfficeNum { get; set; }
public virtual CityStreet Street { get; set; }
}
And I have mapping classes:
public class RegionMap : EntityTypeConfiguration<Region>
{
public RegionMap()
{
this.ToTable("Region");
this.HasKey(r => r.Id);
this.Property(r => r.Name).HasMaxLength(64);
}
}
public class RegionCityMap : EntityTypeConfiguration<RegionCity>
{
public RegionCityMap()
{
this.ToTable("RegionCity");
this.HasKey(rc => rc.Id);
this.HasRequired(rc => rc.Region)
.WithMany(r => r.RegionCities)
.HasForeignKey(rc => rc.RegionId)
.WillCascadeOnDelete(false);
}
}
public class CityStreetMap : EntityTypeConfiguration<CityStreet>
{
public CityStreetMap()
{
this.ToTable("CityStreet");
this.HasKey(cs => cs.Id);
this.HasRequired(cs => cs.City)
.WithMany(c => c.CityStreets)
.HasForeignKey(cs => cs.CityId)
.WillCascadeOnDelete(false);
}
}
public class FullAddressMap : EntityTypeConfiguration<FullAddress>
{
public FullAddressMap()
{
this.ToTable("FullAddress");
this.HasKey(fu => fu.Id);
this.Property(fu => fu.HouseNum).HasMaxLength(16);
this.HasRequired(fu => fu.Street)
.WithMany()
.HasForeignKey(fu => fu.CityStreetId)
.WillCascadeOnDelete(false);
}
}
How i can write mapping class, if i will change class FullAddress as show follow, so that it will justifies its name:
public partial class FullAddress : BaseEntity
{
public int CityStreetId { get; set; }
public string HouseNum { get; set; }
public virtual Region Region { get; set; }
public virtual RegionCity City { get; set; }
public virtual CityStreet Street { get; set; }
}
Can i to map RegionCity through CityStreet and then Region through RegionCity?
You can use NotMapped properties to traverse the hierarchy. Or you can declare extra Navigaion Properties and Foreign Keys that skip levels.
If you change the key structure to use compound keys (which IMO is a best practice here anyway), you can do either one.
eg
public class BaseEntity
{
}
public partial class Region : BaseEntity
{
public int RegionID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public int Timezone { get; set; }
public virtual ICollection<RegionCity> RegionCities { get; } = new HashSet<RegionCity>();
}
public partial class RegionCity : BaseEntity
{
[Key(), Column(Order=0)]
public int RegionId { get; set; }
[Key(), Column(Order = 1)]
public int RegionCityId { get; set; }
public string CityName { get; set; }
[ForeignKey("RegionId")]
public virtual Region Region { get; set; }
public virtual ICollection<CityStreet> CityStreets { get; } = new HashSet<CityStreet>();
}
public partial class CityStreet : BaseEntity
{
[Key(), Column(Order = 0)]
public int RegionId { get; set; }
[Key(), Column(Order = 1)]
public int RegionCityId { get; set; }
[Key(), Column(Order = 3)]
public int CityStreetId { get; set; }
public string StreetName { get; set; }
[ForeignKey("RegionId,RegionCityId")]
public virtual RegionCity RegionCity { get; set; }
public virtual ICollection<FullAddress> FullAddresses { get; } = new HashSet<FullAddress>();
}
public partial class FullAddress : BaseEntity
{
[Key(), Column(Order = 0)]
public int RegionId { get; set; }
[Key(), Column(Order = 1)]
public int RegionCityId { get; set; }
[Key(), Column(Order = 3)]
public int CityStreetId { get; set; }
[Key(), Column(Order = 4)]
public int FullAddressId { get; set; }
public string HouseNum { get; set; }
public string OfficeNum { get; set; }
[ForeignKey("RegionId,RegionCityId,CityStreetId")]
public virtual CityStreet Street { get; set; }
[NotMapped]
public virtual RegionCity RegionCity
{
get
{
return this.Street.RegionCity;
}
set
{
this.Street.RegionCity = value;
}
}
[NotMapped]
public virtual Region Region
{
get
{
return this.Street.RegionCity.Region;
}
set
{
this.Street.RegionCity.Region = value;
}
}
}

Entity Framework Multiple Inheritance with several discriminators

I want to realize structure like this:
public enum TreeType {
Product = 1,
User = 2,
Document = 3
}
public enum ProductType {
Service = 1,
Ware = 2
}
public enum DocumentType {
Order = 1,
Invoice = 2
}
public abstract class Tree
{
[Key]
public Guid Id { get; set; }
[Required]
public string Name { get; set; }
[NotMapped]
public TreeType Type { get; set; }
}
public abstract class Product : Tree
{
[Required]
public string Article { get; set; }
[NotMapped]
public ProductType ProductType { get; set; }
public Tree
{
this.Type = TreeType.Product;
}
}
public class User : Tree
{
[Required]
public string Login { get; set; }
[Required]
public string Password { get; set; }
public User
{
this.Type = TreeType.User;
}
}
public abstract class Document : Tree
{
[Required]
public int PageCount { get; set; }
[Required]
public DateTime Created { get; set; }
[NotMapped]
public DocumentType DocumentType { get; set; }
public Document
{
this.Type = TreeType.Document;
}
}
public class Service : Product
{
[Required]
public int VisitCount { get; set; }
public Service
{
this.ProductType = ProductType.Service;
}
}
public class Ware : Product
{
[Required]
public string StorageName { get; set; }
public Ware
{
this.ProductType = ProductType.Ware;
}
}
public class Order : Document
{
[Required]
public string CustomerName { get; set; }
public Order
{
this.DocumentType = DocumentType.Order;
}
}
public class Invoice : Document
{
[Required]
public string SupplierName { get; set; }
public Invoice
{
this.DocumentType = DocumentType.Invoice;
}
}
public class TreeDbContext : DbContext
{
DbSet<Tree> Trees { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Tree>().ToTable("L_TREES");
.Map<Product>(x => x.Requires("Type").HasValue((int)TreeType.Product)).ToTable("L_PRODUCTS");
.Map<User>(x => x.Requires("Type").HasValue((int)TreeType.User)).ToTable("L_USERS");
.Map<Document>(x => x.Requires("Type").HasValue((int)TreeType.Document)).ToTable("L_DOCUMENTS");
modelBuilder.Entity<Product>()
.Map<Service>(x => x.Requires("ProductType").HasValue((int)ProductType.Service)).ToTable("L_SERVICES");
.Map<Ware>(x => x.Requires("ProductType").HasValue((int)ProductType.Ware)).ToTable("L_WARES");
modelBuilder.Entity<Document>()
.Map<Order>(x => x.Requires("ProductType").HasValue((int)DocumentType.Order)).ToTable("L_ORDERS");
.Map<Invoice>(x => x.Requires("ProductType").HasValue((int)DocumentType.Invoice)).ToTable("L_INVOICES");
}
}
In database it looks like this:
enter image description here
Two-level inheritance I can implement both through TPH, and through TPT, but multi-level inheritance, and even with several descriptors, I can not implement.
As an exit, I can use inheritance and combination, but the implementation is cumbersome and requires a lot of manual action to support in the future.
I tried to implement this architecture, but I did not succeed.
Does anyone know how I can do this?

EF Adding an additional FK?

I have the following 2 entities:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Fixture> Fixtures { get; set; }
}
public class Fixture
{
public int Id { get; set; }
public Result Result { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
}
I have then mapped it like so:
public class FixtureMap : EntityTypeConfiguration<Fixture>
{
public FixtureMap()
{
HasRequired(x => x.AwayTeam).WithMany().HasForeignKey(x => x.AwayTeamId);
HasRequired(x => x.HomeTeam).WithMany().HasForeignKey(x => x.HomeTeamId);
}
}
But when I add a migration, EF is creating an additional FK and column to my Fixture table and I've no idea why? How can I tell it not too?
As you can see its added a column called Team_Id and created an FK from it even tho I have specified the relationship in the mapping?
use this code:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("HomeTeam")]
public virtual ICollection<Fixture> HomeFixtures { get; set; }
[InverseProperty("AwayTeam")]
public virtual ICollection<Fixture> AwayFixtures { get; set; }
}
public class Fixture
{
public int Id { get; set; }
public Result Result { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
[InverseProperty("HomeFixtures")]
[ForeignKey("HomeTeamId ")]
public virtual Team HomeTeam { get; set; }
[InverseProperty("AwayFixtures")]
[ForeignKey("AwayTeamId")]
public virtual Team AwayTeam { get; set; }
}
And :
public class FixtureMap : EntityTypeConfiguration<Fixture>
{
public FixtureMap()
{
HasRequired(x => x.AwayTeam).WithMany().HasForeignKey(x => x.AwayTeamId).willCascadeOnDelete(false);
HasRequired(x => x.HomeTeam).WithMany().HasForeignKey(x => x.HomeTeamId);
}
}