How do I insert nested objects correctly in Ef - sql

I had a problem trying to add object from dto.
I have a DTO like this
public class CustomerCourseSessionDto : IDto
{
public int Id { get; set; }
public int? ConnectorId { get; set; }
public List<SomeObject>? SomeObject { get; set; }
public List<OtherObject>? OtherObject { get; set; }
}
and I'm trying to insert this DTO sent from the UI. I'm using a loop(foreach) for this, but it didn't feel right to me.
Maybe entityframework suggests a method for this, idk...
Other objects are like this
public class SomeObject: IEntity
{
public int Id { get; set; }
public int? ConnectorId { get; set; }
}
public class OtherObject: IEntity
{
public int Id { get; set; }
public int? ConnectorId { get; set; }
}
Thanks for the suggestions.
Here is where I use the loop:
[TransactionScopeAspect]
public IResult AddWithDto(CustomerCourseSessionDto courseSessionDto)
{
foreach (var item in courseSessionDto.Participants)
{
_someObjectService.Add(item);
}
foreach (var item in courseSessionDto.Lessons)
{
_otherObjectService.Add(item);
}
_customerCourseSessionDal.Add(new CustomerCourseSession
{
Id = courseSessionDto.Id,
CustomerCourseId = courseSessionDto.CustomerCourseId,
});
return SuccessResult with message ;
}

You should design your entities to have a link to each table using foreign keys.
public class CustomerCourseSession
{
public int Id { get; set; } // Primary Key
public string Name { get; set; }
public virtual ICollection<CourseParticipant> Participants { get; set; }
public virtual ICollection<CourseLesson> Lessons { get; set; }
}
public class CourseParticipant
{
public int Id { get; set; }
public int CustomerCourseSessionId { get; set; } // Foreign Key from CustomerCourseSession
// other fields here
public virtual CustomerCourseSession CustomerCourseSession { get; set;}
}
public class CourseLesson
{
public int Id { get; set; }
public int CustomerCourseSessionId { get; set; } // Foreign Key from CustomerCourseSession
// other fields here
public virtual CustomerCourseSession CustomerCourseSession { get; set;}
}
Then you can just call:
var entity = MapDtoToEntity(courseSessionDto);
_dbContext.CustomerCourseSessions.Add(entity);
_dbContext.SaveChanges();

Related

Object reference not set to an instance of an object in .net core

I have two model class as;
public class MessageDetailModel
{
[Key]
public int messageDetailsId { get; set; }
public MessageModel messageModel { get; set; }
public string detail { get; set; }
public int senderId { get; set; }
public int customerId { get; set; }
public string phone { get; set; }
public DateTime date { get; set; }
}
and
public class MessageModel
{
[Key]
public int messageId { get; set; }
public int senderId { get; set; }
public int customId { get; set; }
public bool ReadInfo { get; set; }
public virtual List<MessageDetailModel> MessageDetails { get; set; }
}
and it is my context class ;
public virtual DbSet<MessageDetailModel> messageDetails { get; set; }
public virtual DbSet<MessageModel> messages { get; set; }
public virtual DbSet<PersonModel> persons { get; set; }
public virtual DbSet<DirectoryModel> directory { get; set; }
I am trying to get messageId over MessageDetailModel but messageId returns as 0 and I have that error "Object reference not set to an instance of an object"
Console.WriteLine(k.messageModel.messageId); //( k is my var which gets from messagedetail model)
How can ı reach messageId over MessadeDetailModel
There is no current link between your two models that would represent a Foreign Key.
You'd need to do something like this for your model if you want a Foreign Key to link to the related object:
public class MessageDetailModel
{
[Key]
public int messageDetailsId { get; set; }
[ForeignKey("messageId")] // Added Data Annotation for the Foreign Key relationship
public MessageModel messageModel { get; set; }
public string detail { get; set; }
public int senderId { get; set; }
public int customerId { get; set; }
public string phone { get; set; }
public DateTime date { get; set; }
public int messageId { get; set; } // This would be your Foreign Key
}
I've added the messageId column to your MessageDetailModel to match the Primary Key column of your MessageModel as that's necessary for the link to form.
You would use the [ForeignKey("messageId")] Data Annotation above the variable for the MessageModel to determine what value it needs to use when finding the object you want.

Is it possible to create a Domain Class which has Multiple FK Columns to same PK?

I'm a newbie to designing database.
I have problem how to define a domain class which has multiple foreign keys linked with a same primary key.
Here is my model:
namespace OceanFmsSystem.Domain
{
public class ExportTemplate
{
public int Id { get; set; }
public List<ExportBooking> ExportBookings { get; set; }
public string TemplateName { get; set; }
public int CustomerId { get; set; }
public string Incoterms { get; set; }
public string IncotermsDetail { get; set; }
public string PaymentTerm{ get; set; }
public int CountryOriginId { get; set; }
public int CountryDestinationId { get; set; }
}
}
What I want to do is that CountryOriginId & CountryDestinationId should refer to the below class as foreign keys:
namespace OceanFmsSystem.Domain
{
public class Country
{
public int Id { get; set; }
public string CountryCode { get; set; }
public string CountryName { get; set; }
}
}
As far as I know, in EF Core there is an convention which I should name a foreign key as below for migration from code to database.
public type ClassNameOfPrimaryKeyId { get; set;}
Is there any possible way to make this happens?
Yes, possible. Your class should look like this:
public class ExportTemplate
{
//...
public int CountryOriginId { get; set; }
public Country CountryOrigin { get; set; }
public int CountryDestinationId { get; set; }
public Country CountryDestination { get; set; }
}
EF is smart enough to figure the Ids by convention. If you do not wish to follow the convention you can use [ForeignKey] attribute on the properties to configure the FK:
[ForeignKey("Origin")]
public int MyOriginId { get; set; }
public Country Origin { get; set; }

How to set one foreign key references multiple primary keys in EF

I use code-first approach. I want to use just ObjectId property in ObjectScore as foreign key for three relations with Professor (Id) , College (Id) and EducationalGroup (Id), like what's happening at SQL
CONSTRAINT [FK_ObjectScore_Colege] FOREIGN KEY([ObjectId])
CONSTRAINT [FK_ObjectScore_Professer] FOREIGN KEY([ObjectId])
CONSTRAINT [FK_ObjectScore_EducationGroup] FOREIGN KEY([ObjectId])
How to make this relation in Entity Framework (data annotations or fluent api)?
Thanks all
public class Professor : Person
{
public int ProfessorCode { get; set; }
public virtual ICollection<EducationalGroup> EducationalGroups { get; set; }
public virtual ICollection<College> Colleges { get; set; }
public virtual ICollection<ObjectScore> ObjectScores { get; set; }
}
public class College : BaseClass
{
public int CollegeCode { get; set; }
public virtual ICollection<Professor> Professors { get; set; }
public virtual ICollection<EducationalGroup> EducationalGroups { get; set; }
public virtual ICollection<ObjectScore> ObjectScores { get; set; }
}
public class EducationalGroup : BaseClass
{
public int CollegeCode { get; set; }
public virtual ICollection<Professor> Professors { get; set; }
public virtual College College { get; set; }
public virtual ICollection<ObjectScore> ObjectScores { get; set; }
}
public class ObjectScore
{
public Guid Id { get; set; }
public int CurrentScore { get; set; }
public virtual Term Term { get; set; }
public virtual Score Score { get; set; }
public int ObjectId { get; set; }
}
and my BaseClass and Person classes:
public class Person : BaseClass
{
public string Family { get; set; }
}
public class BaseClass
{
public BaseClass()
{
IsActive = false;
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? LastModifiedDate { get; set; }
public bool IsActive { get; set; }
}

Mapping multiple properties of a same type with HasMany via automapping

I am trying to map properties of the same type on a OneToMany association. I tried to distinguish with Description but kinda stuck here.
public class User
{
public virtual int UserId { get; set; }
public virtual string UserName { get; set; }
[Description("From")]
public virtual IList<Message> FromMessageList { get; set; }
[Description("To")]
public virtual IList<Message> ToMessageList { get; set; }
}
public class Message
{
public virtual int MessageId { get; set; }
public virtual string Text { get; set; }
[Description("From")]
public virtual User FromUser { get; set; }
[Description("To")]
public virtual User ToUser { get; set; }
}
public class DefaultHasManyConvention : IHasManyConvention
{
public void Apply(IOneToManyCollectionInstance instance)
{
if (instance.OtherSide.Property.GetDescription() == instance.Member.GetDescription())
{
if (instance.Member.GetDescription() != null)
instance.Key.Column(instance.Member.GetDescription() + "Id");
else
instance.Key.Column(instance.OtherSide.Property.Name + "Id");
instance.Fetch.Select();
}
}
}
public class DefaultReferenceConvention : IReferenceConvention
{
public void Apply(IManyToOneInstance instance)
{
if (instance.Property.GetDescription() != null)
instance.Column(instance.Property.GetDescription() + "Id");
else
instance.Column(instance.Property.Name + "Id");
instance.Fetch.Select();
}
}
For one to many relationships I generally use coding like :
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
[Description("From")]
public virtual ICollection<Message> FromMessageList { get; set; }
[Description("To")]
public virtual ICollection<Message> ToMessageList { get; set; }
}
public class Message
{
public int MessageId { get; set; }
public string Text { get; set; }
[Description("From")]
public virtual User FromUser { get; set; }
// From user foreign key column
[ForeignKey("FromUser")]
public int FromUserId {get;set;}
[Description("To")]
public virtual User ToUser { get; set; }
// ToUser foreign key column
[ForeignKey("ToUser")]
public int ToUserId {get;set;}
}
Try to use ICollection instead of IList - this solved many issues for me.
Add foreign key column names; it makes mapping simpler and filtering in queries easier.

Entity Relationship - CodeFirst - Multiple Relationships

I'm trying to create the following object for my DB (CodeFirst),
And i have the following problem:
when i try to add new one or many object to a new srevice provider slots (as follows:)
ServiceProviderSlots slot = new ServiceProviderSlots();
slot.ServiceProviderID = 1;
slot.SlotServices.Add(new ServiceProviderServices() { ServiceProviderServiceID = 1 });
ctx.ServiceProviderSlots.Add(slot);
I get an error, because i'm not creating a new object, and i'm missing foreign keys, but i wish to use data which already exists on that table.
ERROR:
{"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_dbo.ServiceProviderServices_dbo.ServiceProviders_ServiceProviderID\". The conflict occurred in database \"qunadodb\", table \"dbo.ServiceProviders\", column 'ServiceProviderID'.\r\nThe statement has been terminated."}
Maybe it's related to this?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
Which i used becuase i couldn't create the db otherwise, i had another error.
See below structure:
public class BusinessCategories
{
[Key]
public int CategoryID { get; set; }
public String Title { get; set; }
}
public class BusinessTypes
{
[Key]
public int TypeID { get; set; }
public String Title { get; set; }
public int CategoryID { get; set; }
public virtual BusinessCategories Categories { get; set; }
}
public class ServiceProviders
{
[Key]
public int ServiceProviderID { get; set; }
public String Name { get; set; }
public Int32 TypeID { get; set; }
public virtual BusinessTypes Type { get; set; }
}
public class ServiceProviderServices
{
[Key]
public Int32 ServiceProviderServiceID { get; set; }
public String Price { get; set; }
public Int32 ServiceProviderID { get; set; }
public virtual ServiceProviders ServiceProvider { get; set; }
public Int32 SubServiceID { get; set; }
public virtual SubServices SubService { get; set; }
}
public class ServiceProviderSlots
{
public ServiceProviderSlots()
{
SlotServices = new List<ServiceProviderServices>();
}
[Key]
public Int32 SlotID { get; set; }
public String Name { get; set; }
public Int32 ServiceProviderID { get; set; }
[ForeignKey("ServiceProviderID")]
public virtual ServiceProviders ServiceProvider { get; set; }
public virtual ICollection<ServiceProviderServices> SlotServices { get; set; }
}
this message means that you probably yet have a ServiceProvider with Id = 1 in the database.
in this cas you have to attach the entity to the context.