Fluent Api Composite Primary Key - entity-framework

I have this configuration:
public class Cliente
{
public int ClienteId { get; set; }
public Empresa Empresa { get; set; }
public int TipoDocumento { get; set; }
public string Rsocial { get; set; }
}
public class Empresa
{
public int EmpresaId { get; set; }
public int Rut { get; set; }
public List<Producto> Productos { get; set; }
}
and in the context class I wrote this configuration:
modelBuilder.Entity<Cliente>()
.HasKey(cl => new { cl.ClienteId, cl.Empresa.EmpresaId})
.HasName("PK_cliente");
I get this error:
An error occurred creating the DB.
System.ArgumentException: The expression 'cl => cl.Empresa.EmpresaId' is not a valid member access expression. The expression should represent a simple property or field access: 't => t.MyProperty'. (Parameter 'memberAccessExpression')

Related

EFCore Generic Repository and UnitOfWork Design Pattern

when im trying to create new data and save it, im getting error at the
public int Complete()
{
return _context.SaveChanges();
}
and error is saying me that:
The value of 'Agency.ID' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known. .
i have a Base class like that:
public class Base
{
protected Base()
{
CreatedDate = DateTime.Now;
IsDeleted = false;
ModifiedDate = null;
}
public int ID { get; set; }
public int? CreatedUserId { get; set; }
public int? ModifiedUserId { get; set; }
public string CreatedUserType { get; set; }
public string ModifiedUserType { get; set; }
public DateTime? CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
public bool? IsActive { get; set; }
public bool? IsDeleted { get; set; }
}
i have a Agency class like that :
public class Agency : Base
{
public Agency()
{
AgencyIsComplated = false;
}
[Required, StringLength(255)]
public string AgencyName { get; set; }
[Required, StringLength(255)]
public string AgencyPhoto { get; set; }
[Required, StringLength(255)]
public string AgencyEMail { get; set; }
[Required, StringLength(13)]
public string AgencyPhone { get; set; }
[StringLength(13)]
public string AgencyBPhone { get; set; }
[StringLength(255)]
public string AgencyInfo { get; set; }
[Required, StringLength(255)]
public string AgencyTitle { get; set; }
[Required, StringLength(255)]
public string AgencyLink { get; set; }
public int AgencyExportArea { get; set; } // Join table ile yapılacak,ayrı bir tabloda tutulacak
[Required, StringLength(255)]
public string AgencyInstagram { get; set; }
public string AgencyTwitter { get; set; }
public string AgencyFacebook { get; set; }
public string AgencyLinkedin { get; set; }
public string AgencyYoutube { get; set; }
public bool AgencyIsComplated { get; set; }
[ForeignKey("CompanyID")]
public Company Company { get; set; }
[ForeignKey("LogID")]
public Log Log { get; set; }
public virtual ICollection<AgencyCompany> AgencyCompanies { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Log> Logs { get; set; }
}
public class AgencyConfiguration : IEntityTypeConfiguration<Agency>
{
public void Configure(EntityTypeBuilder<Agency> builder)
{
builder.HasKey(agency => agency.ID);
builder.HasMany(a => a.Logs)
.WithOne(a => a.Agency)
.HasForeignKey(a=>a.ID)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(us => us.Users)
.WithOne(us => us.Agency)
.HasForeignKey(au=>au.ID)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(ac => ac.AgencyCompanies)
.WithOne(ac => ac.Agency)
.OnDelete(DeleteBehavior.Restrict);
}
}
and i have got a UnitOfWork like that:
public class UnitOfWork : IUnitOfWork
{
private TradeTurkDBContext _context;
public UnitOfWork(TradeTurkDBContext context)
{
_context = context;
RepositoryAgency = new RepositoryAgency(_context);
}
public IRepository Repository { get; private set; }
public IRepositoryAgency RepositoryAgency { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
im inheriting that ID on my Base Model.
the problem is getting solved when im not defining ID in the base model but i allready set up my mapping on it.
so how can i solve that error without using AgencyID in the Agency model ?
The foreign key is in the details (or child) table. Therefore, e.g. a user, should have an AgencyId as foreign key.
builder.Entity<User>()
.HasOne(u => u.Agency)
.WithMany(a => a.Users)
.HasForeignKey(u => u.AgencyId)
.OnDelete(DeleteBehavior.Restrict);
This key automatically points to the primary key of the master (or parent) table.
User.ID is a primary key. User.AgencyId is a foreign key which (automatically) relates to the primary key Agency.ID.
E.g. see: Configure One-to-Many Relationships using Fluent API in Entity Framework Core

EF Core Include Grandchild GenericRepository

I'm using a GenericRepository to work with Eager Loading on EF Core, in this case i can loading CategoriaNutrientes but if i try to load Nutriente
categoriaService.FindBy((i => i.CategoriaNutrientes.Select(x=>x.Nutriente)))
i've got this error:
System.InvalidOperationException: 'The property expression 'i => {from
ManyToManyChild x in [i].ManyToManyChilds select [x].GrandChild}'
is not valid. The expression should represent a property access: 't =>
t.MyProperty'. For more information on including related data, see
http://go.microsoft.com/fwlink/?LinkID=746393.'
public class Categoria:BaseEntidadeExecutora
{
public Int64 Id { get; set; }
public string NomeCategoria { get; set; }
public Int64 QtdeMinimaRefeicao { get; set; }
public string FormaCalculo { get; set; }
public Int64 NecessidadeDiariaMinima { get; set; }
public ICollection<CategoriaNutriente> CategoriaNutrientes { get; set; }
public ICollection<UnidadeEnsinoCategoria> UnidadeEnsinoCategorias { get; set; }
}
public class CategoriaNutriente : BaseEntity
{
public Int64 IdCategoria { get; set; }
public Categoria Categoria {get;set;}
public Int64 IdNutriente { get; set; }
public Nutriente Nutriente { get; set; }
public Int64 NecessidadeNutricional { get; set; }
}
categoriaService.FindBy((i => i.CategoriaNutrientes.Select(x=>x.Nutriente)))
public IEnumerable<T> FindBy(params Expression<Func<T, object>>[] includes)
{
IQueryable<T> set = entities;
var entity = (includes.Aggregate(set, (current, include) => current.Include(include)).ToList() ?? default(ICollection<T>));
}

EF code first - one-to-one-or-zero

I have 2 entities:
public partial class GPSdevice
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public GPSdevice()
{
}
public int ID { get; set; }
public string UserName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual Truck Truck { get; set; }
}
public partial class Truck
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Truck()
{
}
public int TruckID { get; set; }
public string TruckNo { get; set; }
public string Make { get; set; }
[ForeignKey("GPSdevice")]
public int? GPSdeviceID { get; set; }
public virtual GPSdevice GPSdevice { get; set; }
}
I want to create a relationship one-to-one-or-zero (each GPSdevice can be linked to any truck (but to one and only one) or not linked at all)
I write the following code:
modelBuilder.Entity<GPSdevice>()
.HasOptional(e => e.Truck)
.WithOptionalPrincipal()
.WillCascadeOnDelete(false);
but it creates the following migration:
public override void Up()
{
AddColumn("dbo.Truck", "GPSdevice_ID", c => c.Int());
CreateIndex("dbo.Truck", "GPSdeviceID");
CreateIndex("dbo.Truck", "GPSdevice_ID");
AddForeignKey("dbo.Truck", "GPSdeviceID", "dbo.GPSdevices", "ID");
AddForeignKey("dbo.Truck", "GPSdevice_ID", "dbo.GPSdevices", "ID");
}
why it creates one more field and how to use the current field GPSdeviceID instead?
ADDED:
If I remove
public int? GPSdeviceID { get; set; }
and add MapKey:
modelBuilder.Entity<GPSdevice>()
.HasOptional(e => e.Truck)
.WithOptionalPrincipal(e=>e.GPSdevice).Map(p=>p.MapKey("GPSdeviceID"))
.WillCascadeOnDelete(false);
in result I get the following migration code:
public override void Up()
{
CreateIndex("dbo.Truck", "GPSdeviceID");
AddForeignKey("dbo.Truck", "GPSdeviceID", "dbo.GPSdevices", "ID");
}
then I get the following error:
There are no primary or candidate keys in the referenced table
'dbo.GPSdevices' that match the referencing column list in the foreign
key 'FK_dbo.Truck_dbo.GPSdevices_GPSdeviceID'. Could not create
constraint or index. See previous errors.
Use this :
public partial class GPSdevice
{
public GPSdevice()
{
}
public int ID { get; set; }
public string UserName { get; set; }
public virtual Truck Truck { get; set; }
}
public partial class Truck
{
public Truck()
{
}
public int TruckID { get; set; }
public string TruckNo { get; set; }
public string Make { get; set; }
public virtual GPSdevice GPSdevice { get; set; }
}
modelBuilder.Entity<GPSdevice>()
.HasOptional(o => o.Truck)
.WithRequired(ad => ad.GPSdevice);
modelBuilder.Entity<Truck>()
.HasKey(e => e.TruckID);

InvalidOperationException: The entity type 'object' requires a key to be defined

Entity-framework 7.
[Table("Settings")]
public class Setting
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public object DefaultValue { get; set; }
public string Classification { get; set; }
public FacilitySettingOverride FacilitySettingOverride { get; set; }
}
[Table("FacilitySettingOverride")]
public class FacilitySettingOverride
{
[Key]
[ForeignKey("FacilityId")]
public int FacilityId { get; set; }
public object Value { get; set; }
[ForeignKey("SettingId")]
public int SettingId { get; set; }
public virtual ICollection<Setting> Settings { get; set; }
}
[Table("Facilities")]
public class Facility
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<FacilitySettingOverride> FacilitySettingOverrides { get; set; }
}
When run the code
private IEnumerable<FacilitySettingOverride> GetFacilityBandwidthSettings
{
get
{
List<FacilitySettingOverride> settingList;
using (SettingDbContext context = new SettingDbContext())
{
settingList = context.FacilitySettingOverride.ToList();
}
return settingList;
}
}
Then get the exception:
InvalidOperationException: The entity type 'object' requires a key to be defined.
The context is:
public class SettingDbContext : DbContext
{
public DbSet<Setting> Settings { get; set; }
public DbSet<FacilitySettingOverride> FacilitySettingOverride { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=13.53.63.74;Initial Catalog=AAAAA;User ID=sa;password=password);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
However if I change the object to string for Value or DefaultValue in POCO then no exception. But the type in the database is sql_variant. I have to use the type object.
It seems that Data annotations are not yet supported so you will need to use the Fluent API for configuration.
See: https://github.com/aspnet/EntityFramework/issues/1913#issuecomment-86662854

Entity Framework Code First and Invalid Object Name Error

I have a composite table called ImporterState, that are tied to a table called Importer and State. The error happens here context.Importers.Include(q => q.States). Why is this happening?
{"Invalid object name 'ImporterStates'."}
[Table("HeadlineWebsiteImport", Schema = "GrassrootsHoops")]
public class Importer
{
public int Id { get; set; }
public string Name { get; set; }
public string RssUrl { get; set; }
public string Type { get; set; }
public string Keywords { get; set; }
public bool Active { get; set; }
public DateTime DateModified { get; set; }
public DateTime DateCreated { get; set; }
public int WebsiteId { get; set; }
public HeadlineWebsite Website { get; set; }
[InverseProperty("Importers")]
public ICollection<State> States { get; set; }
}
[Table("State", Schema = "GrassrootsHoops")]
public class State
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Abbr { get; set; }
[InverseProperty("States")]
public ICollection<Headline> Headlines { get; set; }
[InverseProperty("States")]
public ICollection<Importer> Importers { get; set; }
}
The many to many is not possible using attributes only.
try using something like:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Importer>()
.HasMany(i => i.States)
.WithMany(s => s.Importers)
.Map(m =>
{
m.MapLeftKey("ImporterId");
m.MapRightKey("StateId");
m.ToTable("ImporterState");
});
}