EF 1 to 1 required relationship - c#

I have an attribute which looks like this:
public class CameraAttribute
{
public int Id { get; set; }
public int ProductId { get; set; }
public string CompatibleMemory { get; set; }
[MaxLength(255)] public string WhiteBalance { get; set; }
[MaxLength(255)] public string SceneModes { get; set; }
[MaxLength(255)] public string ShootingModes { get; set; }
[MaxLength(100)] public string PhotoEffects { get; set; }
[MaxLength(255)] public string CameraPlayback { get; set; }
public bool Tripod { get; set; }
public bool DirectPrinting { get; set; }
[MaxLength(50)] public string Colour { get; set; }
public CameraAttributePicture Picture { get; set; }
public CameraAttributeVideo Video { get; set; }
public CameraAttributeAudio Audio { get; set; }
public CameraAttributeBattery Battery { get; set; }
public CameraAttributeDimension Dimensions { get; set; }
public CameraAttributeDisplay Display { get; set; }
public CameraAttributeLightExposure Exposure { get; set; }
public CameraAttributeFlash Flash { get; set; }
public CameraAttributeFocusing Focusing { get; set; }
public CameraAttributeInterface Interface { get; set; }
public CameraAttributeLens Lens { get; set; }
public CameraAttributeNetwork Network { get; set; }
public CameraAttributeShutter Shutter { get; set; }
[ForeignKey("ProductId")] public Product Product { get; set; }
}
and the Audio looks like this:
public class CameraAttributeAudio
{
public int Id { get; set; }
public int AttributeId { get; set; }
[MaxLength(50)] public string SupportedFormats { get; set; }
[ForeignKey("AttributeId")] public CameraAttribute Attributes { get; set; }
}
I have set up some mapping in my DbContext like this:
modelBuilder.Entity<CameraAttribute>().HasRequired(m => m.Audio).WithRequiredPrincipal(m => m.Attributes).WillCascadeOnDelete(true);
but when I try to run the command add-migration I get this error:
CameraAttribute_Audio_Target: : Multiplicity is not valid in Role 'CameraAttribute_Audio_Target' in relationship 'CameraAttribute_Audio'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
As you can see from the Attribute class all the properties throw this error.
Does anyone know why and how I can resolve it?

I think the problem is that CameraAttributeAudio class has its own Id property as well while it is unnecessary in a one-to-one relationship because AttributeId can identify both the CameraAttribute and the CameraAttributeAudio. It should use the AttributeId as its primary [Key].
public class CameraAttributeAudio
{
[Key]
[ForeignKey("Attributes")]
public int AttributeId { get; set; }
[MaxLength(50)]
public string SupportedFormats { get; set; }
public CameraAttribute Attributes { get; set; }
}
I moved the [ForeignKey] attribute to the AttributeId property so that the annotations are in one place. Although it is also correct to have it on the Attributes property.

Related

EF Core Invalid Column Name (Foreign Keys)

I'm using EF Core 2.2
the Code with the error
var ClientCase= _context.Client_Cases.Include(a=>a.Case_Sessions). FirstOrDefault(x => x.Id == id);
The Error
System.Data.SqlClient.SqlException: 'Invalid column name
'Client_CaseId'. Invalid column name 'Case_LevelId'. Invalid column
name 'Client_CaseId'. Invalid column name 'Court_CircleId'. Invalid
column name 'Court_HallId'.'
Entities
1- Parent Client_Case
public class Client_Cases
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string Opponent { get; set; }
public DateTime? StartDate { get; set; }
public DateTime Recieve_Date { get; set; }
[ForeignKey("Clients")]
public long? ClientID { get;set;}
public Clients Client { get; set; }
[ForeignKey("Case_Levels")]
public long? LevelID { get; set; }
public virtual Case_Levels Case_Levels { get; set; }
[ForeignKey("Case_Types")]
public long? TypeID { get; set; }
public virtual Case_Types Case_Types { get; set; }
[ForeignKey("Court_Circles")]
public long? CircleID { get; set; }
public virtual Court_Circles Court_Circles { get; set; }
[ForeignKey("Court_Halls")]
public long? HallID { get; set; }
public virtual Court_Halls Court_Halls { get; set; }
[ForeignKey("Courts")]
public long? CourtID { get; set; }
public virtual Courts Court { get; set; }
[ForeignKey("Case_Status")]
public long? StatusID { get; set; }
public Case_Status Case_Status { get; set; }
[ForeignKey("Lawyers")]
public long? LawyerID { get; set; }
public virtual LawyersData Lawyers { get; set; }
public string Description { get; set; }
public string Code { get; set; }
public string CaseNo { get; set; }
public List<Case_Sessions> Case_Sessions { get; set; }
}
Detail Entity Case_Session
public class Case_Sessions
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("Client_Cases")]
public long? CaseID { get;set;}
public Client_Cases Client_Case { get; set; }
[ForeignKey("Case_Levels")]
public long? LevelID { get; set; }
public Case_Levels Case_Level { get; set; }
[ForeignKey("Court_Circles")]
public long? CircleID { get; set; }
public Court_Circles Court_Circle { get; set; }
[ForeignKey("Court_Halls")]
public long? HallID { get; set; }
public Court_Halls Court_Hall { get; set; }
[ForeignKey("Case_Status")]
public long? StatusID { get; set; }
public Case_Status Case_Status { get; set; }
public DateTime Session_Date { get; set; }
public string Judge_Name { get; set; }
public string Session_Result { get; set; }
public string Notes { get; set; }
}
If I get the parent without including the child it works.
If I get the details, it works.
I know the error that EF Core Create its own naming convention for the Foreign keys
but I think the tag Foreign Key override that naming convention
Now where I am wrong?
[ForeignKey("")] Mean? name the property you have added in class to become a foreign key. e.g:
public long? CaseID { get;set;}
[ForeignKey("CaseID")]
public Client_Cases Client_Case { get; set; }
public long? CircleID { get; set; }
[ForeignKey("CircleID")]
public Court_Circles Court_Circle { get; set; }
You can use annotations like above, In your case, below correction needed:
[ForeignKey("Client")] // it should be [ForeignKey("Client")] not an extra s if you using entities name in annotation.
public long? ClientID { get;set;}
public Clients Client { get; set; }
this should be your relationship for lawyer:
[ForeignKey("Lawyers")]
public long? LawyersID { get; set; }
public virtual LawyersData Lawyers { get; set; }
I am assuming that the type of primary key in LawyersData table is long?.

There are no primary in referenced table 'x' that match referencing column foreign key ".y"

There are no primary or candidate keys in the referenced table 'dbo.Client_Master' that match the referencing column list in the foreign key 'FK_dbo.Client_Question_Master_dbo.Client_Master_client_id'.
Could not create constraint or index. See previous errors.
My Client_Master Model
public class Client_Master
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Client_Id { get; set; }
public string Client_Name { get; set; }
public string Client_Address { get; set; }
public string Client_Email { get; set; }
public string Client_Phone { get; set; }
[DefaultValue(" ")]
public string Client_Country { get; set; }
[DefaultValue(" ")]
public string Client_State { get; set; }
[DefaultValue(" ")]
public string Client_Postcode { get; set; }
public bool Is_Active { get; set; }
public long? Created_By { get; set; }
public DateTime? Created_Date { get; set; }
[ForeignKey("Business_Master")]
public long? Business_Id { get; set; }
[ForeignKey("Categories")]
public long? Category_Id { get; set; }
public virtual Categories Categories { get; set; }
public virtual Business_Master Business_Master { get; set; }
[JsonIgnore]
public virtual ICollection<Client_Question_Master> Client_Question_Master { get; set; }
}
And My Client_Question_Master Modal
public class Client_Question_Master
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long client_question_master_id { get; set; }
[ForeignKey("Client_Master")]
public long? client_id { get; set; }
public virtual Client_Master Client_Master { get; set; }
[ForeignKey("Question_Types")]
public long? question_type_id { get; set; }
public virtual Question_Types Question_Types { get; set; }
public string question { get; set; }
public long order_no { get; set; }
public bool isContribute { get; set; } = true;
[ForeignKey("Section_Master")]
public long? section_id { get; set; }
public virtual Section_Master Section_Master { get; set; }
public double amount { get; set; }
public bool isActive { get; set; } = true;
public bool isRequired { get; set; } = true;
public bool isComment { get; set; } = true;
public string values { get; set; }
public bool isRevenue { get; set; }
public bool isStaff { get; set; }
public bool isMarketing { get; set; }
public DateTime created_date { get; set; } = DateTime.Now;
}
After add-migration during updating database it is giving me error.
Your usage of the ForeignKey attribute is the wrong way round, when using a nullable foreign key.
For example you use:
[ForeignKey("Client_Master")]
public long? client_id { get; set; }
public virtual Client_Master Client_Master { get; set; }
However it should be:
public long? client_id { get; set; }
[ForeignKey("client_id")]
public virtual Client_Master Client_Master { get; set; }
You tell EntityFramework what property is the foreign key. This prevent it from creating a field that has the same datatype as the primary key.
Check your edmx file.Edmx may not have that column as Primary key in another table which you are using as foreign key.

EF core 2.0, OwnsOne in TPH model classes

I have problem when I try to migrate my model in EF Core 2.0.
public class Profile
{
[Key]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public ExternalUser User { get; set; }
}
public class OrganizationCustomerProfile : Profile
{
public string CompanyName { get; set; }
public Address LegalAddress { get; set; }
public Address ActualAddress { get; set; }
public BusinessRequisites Requisites { get; set; }
public string President { get; set; }
public IEnumerable<ContactPerson> ContactPerson { get; set; }
}
public class PersonCustomerProfile : Profile
{
public FullName Person { get; set; }
public Address Address { get; set; }
public string PhoneNumber { get; set; }
}
public class ContactPerson
{
[Key]
public Guid Id { get; set; }
public FullName Person { get; set; }
public string Rank { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public Guid ProfileId { get; set; }
public Profile Profile { get; set; }
}
Here I want to add complex datatypes Address and BusinessRequisites, which are:
public class BusinessRequisites
{
public string OGRN { get; set; }
public string INN { get; set; }
public string KPPCode { get; set; }
public string SettlementAccount { get; set; }
public string RCBIC { get; set; }
public string CorrespondentAccount { get; set; }
public string BankName { get; set; }
}
public class Address
{
public string FullAddress { get; set; }
public float Latitude { get; set; }
public float Longtitude { get; set; }
}
Code which I use for TPH binding:
public DbSet<Profile> UserProfiles { get; set; }
public DbSet<ContactPerson> ContactPerson { get; set; }
public DbSet<OrganizationCustomerProfile> OrganizationCustomerProfile { get; set; }
...
modelBuilder.Entity<Profile>().HasKey(u => u.Id);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.ActualAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.LegalAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.Requisites);
But when I try to make a migration, I get an error:
"Cannot use table 'UserProfiles' for entity type
'OrganizationCustomerProfile.ActualAddress#Address' since it has a
relationship to a derived entity type 'OrganizationCustomerProfile'.
Either point the relationship to the base type 'Profile' or map
'OrganizationCustomerProfile.ActualAddress#Address' to a different
table."
So, what the reason of this error? Is it not possible to create hierarchy inheritance in EF Core 2.0?
Thank you!
It seems like this isn't supported at the moment:
https://github.com/aspnet/EntityFrameworkCore/issues/9888

Entity Framework - Update action and Automapper

For example, I have the following infrastructure class:
[Table("GeoHistory")]
public partial class GeoHistory
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int DriverId { get; set; }
[StringLength(50)]
public string Name { get; set; }
public string Description { get; set; }
[StringLength(100)]
public string GeofenceLocation { get; set; }
[StringLength(100)]
public string GeofencePrevious { get; set; }
[StringLength(20)]
public string StateLocation { get; set; }
[StringLength(20)]
public string StatePrevious { get; set; }
public DateTime? DateTime { get; set; }
[StringLength(5)]
public string Heading { get; set; }
public decimal? Speed { get; set; }
[StringLength(50)]
public string Status { get; set; }
}
and the following View class (let's forget about domain layer):
public class GeoHistoryViewModel
{
public int Id { get; set; }
public int? CompanyId { get; set; }
public int? DriverId { get; set; }
[StringLength(50)]
public string Name { get; set; }
public string Description { get; set; }
}
as we can see, we edit only part of field list.
Now, we want to update data in DB. Of course, we can write like:
Infrastructure.Main.GeoHistory geoHistory = db.GeoHistories.Find(id);
geoHistory.CompanyId = model.CompanyId;
geoHistory.DriverId = model.DriverId;
geoHistory.Name = model.Name;
........
db.SaveChanges();
It works. But I want to use Automapper. And if I try to do the following:
Infrastructure.Main.GeoHistory geoHistory = mapper.Map<Infrastructure.Main.GeoHistory>(model);
db.GeoHistories.Attach(geoHistory);
db.Entry(geoHistory).State = EntityState.Modified;
db.SaveChanges();
It works, but of course remove values of fields, which are not exist in View Model, but exist in infrastructure class. How to use automapper, but don't lost these fields?

Mapping complex DTOs to entities with automapper

I want to map from
LDTTicketUploadDTO[] to IEnumerable<LDTTicket>
The mappings are created in this method and at the end I map the data.
public void UploadLDTTickets(LDTTicketUploadDTO[] ticketDTOs)
{
Mapper.CreateMap<LDTTicketUploadDTO, LDTTicket>();
Mapper.CreateMap<LDTTicketDTO, LDTTicket>();
Mapper.CreateMap<LDTCustomerDTO, LDTCustomer>();
Mapper.CreateMap<LDTDeviceDTO, LDTDevice>();
Mapper.CreateMap<LDTUnitDTO, LDTUnit>();
Mapper.CreateMap<LDTCommandDTO, LDTCommand>();
Mapper.CreateMap<LDTCommandParameterDTO, LDTCommandParameter>();
Mapper.CreateMap<LDTObjectDTO, LDTObject>();
Mapper.CreateMap<LDTControlFileDTO, LDTControlFile>();
Mapper.CreateMap<LDTDeviceDTO, LDTDevice>();
Mapper.CreateMap<LDTLanguageDTO, LDTLanguage>();
Mapper.CreateMap<LDTObjectBitDTO, LDTObjectBit>();
var tickets = Mapper.Map<IEnumerable<LDTTicketUploadDTO>, IEnumerable<LDTTicket>>(ticketDTOs);
// do something with tickets
}
This is how the DTO´s are structured:
public class LDTTicketUploadDTO
{
public LDTTicketDTO Ticket { get; set; }
public LDTDeviceDTO Device { get; set; }
public LDTCustomerDTO Customer { get; set; }
}
public enum TicketStatus
{
New,
InProgress,
Done
}
public class LDTTicketDTO
{
public bool UploadNeeded { get; set; }
public string TicketNumber { get; set; }
public TicketStatus Status { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedOn { get; set; }
public string AssignedTo { get; set; }
public IEnumerable<LDTUnitDTO> Units { get; set; }
}
public class LDTUnitDTO
{
public int Id { get; set; }
public string FunctionUnit { get; set; }
public int FunctionUnitAddress { get; set; }
public string Zone { get; set; }
public int ZoneUnitAddress { get; set; }
public string Object { get; set; }
public int ObjectAddress { get; set; }
public IEnumerable<LDTCommandDTO> Commands { get; set; }
}
and more...
What works is that these properties are correctly mapped to their counterpart entities:
public LDTDeviceDTO Device { get; set; }
public LDTCustomerDTO Customer { get; set; }
What works NOT is that this property is not mapped:
public LDTTicketDTO Ticket { get; set; }
This is how the Entities are structured:
public class LDTTicket
{
[Key, Column(Order = 0)]
[Required]
public string SerialNumber { get; set; }
[Key, Column(Order = 1)]
[Required]
public string TicketNumber { get; set; }
[Required]
public DateTime CreatedOn { get; set; }
[Required]
public string AssignedTo { get; set; }
public TicketStatus Status { get; set; }
public string CreatedBy { get; set; }
public bool UploadNeeded { get; set; }
public virtual LDTCustomer Customer { get; set; }
public virtual LDTDevice Device { get; set; }
public virtual ICollection<LDTUnit> Units { get; set; }
}
ONLY the Customer and Device property are mapped in the LDTTicket
What is wrong with my configuration?
It's expecting to populate a LDTTicket sub-property on the ticket, not the matching properties of the ticket itself. Create direct mappings onto the ticket from the Ticket subproperty of the source directly onto the matching properties of the destination. NOTE: You only need to define your mappings once, not per method execution. Mappings should be defined at app start up and thereafter used.
public void UploadLDTTickets(LDTTicketUploadDTO[] ticketDTOs)
{
Mapper.CreateMap<LDTTicketUploadDTO, LDTTicket>();
.ForMember(d => d.SerialNumber, m => m.MapFrom(s => s.Ticket.SerialNumber))
...
//Mapper.CreateMap<LDTTicketDTO, LDTTicket>(); You don't need this
Mapper.CreateMap<LDTCustomerDTO, LDTCustomer>();
Mapper.CreateMap<LDTDeviceDTO, LDTDevice>();
...
}

Categories