I want to add 2 entities at once - c#

I want to add 2 entities at once. When I want to add an offer, let the offer detail be added at the same time.
But let's add more than one detail to a quote.
I can't do this. I will be glad if you help.
public class Offer
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int CompanyContactId { get; set; }
public int OfferNumber { get; set; }
public string Annotations { get; set; }
public string CommercialConditions { get; set; }
public string TimeInformation { get; set; }
public decimal ProfitRate { get; set; }
public DateTime Date { get; set; }
public DateTime ValidityDate { get; set; }
public Currency Currency { get; set; }
public Status Status { get; set; }
//Navigation Property
public virtual Company Company { get; set; }
public virtual CompanyContact CompanyContact { get; set; }
public virtual List<OfferDetail> OfferDetail { get; set; }
public class OfferDetail
{
//public int Id { get; set; }
public int OfferId { get; set; }
public int RowNumber { get; set; }
public int Quantity { get; set; }
public string Description { get; set; }
public decimal UnitPrice { get; set; }
public decimal TotalPrice { get; set; }
public string Definition { get; set; }
public Boolean Optional { get; set; }
public decimal UnitProfit { get; set; }
public decimal UnitCost { get; set; }
//public Currency Currency { get; set; }
//Navigation Properties
public Offer Offer { get; set; }
When I add the offer table to the database, the offer details are also added. But let another detail be added to a quote.
public async Task<Result> AddOffer(OfferInfo offerInfo)
{
try
{
var vOffer = new Offer
{
Id = offerInfo.Id,
CompanyId = offerInfo.CompanyId,
CompanyContactId = offerInfo.CompanyContactId,
OfferNumber = offerInfo.OfferNumber,
Annotations = offerInfo.Annotations,
CommercialConditions = offerInfo.CommercialConditions,
TimeInformation = offerInfo.TimeInformation,
ProfitRate = offerInfo.ProfitRate,
Date = offerInfo.Date,
ValidityDate = offerInfo.ValidityDate,
}; _context.Offers.Add(vOffer);
await _context.SaveChangesAsync();
return Result.PrepareSuccess();
}
catch (Exception vEx)
{
return Result.PrepareFailure(vEx.Message);
}
}
I can add from the model I created here.
This way I want to add both. Thanks in advance.

If you assign list of OfferDetail to Offer details entities will automatically be added to adequate table.
It should be something like this:
var vOffer = new Offer
{
// set all your properties of offer here
OfferDetails = new []
{
new OfferDetail {/*init details here*/},
// you can add more of details objects here
}
}

Chicken and egg problem, but there is a solution if you define constructors in OfferDetail that require the Offer and then add themselves to the List<OfferDetail>.
public class Offer
{
public Offer()
{
OfferDetail = new List<OfferDetail>();
}
//Navigation Property
public List<OfferDetail> OfferDetail { get; }
}
public class OfferDetail
{
public OfferDetail(Offer offer)
{
Offer = offer;
offer.OfferDetail.Add(this);
}
public int OfferId { get => Offer.Id; }
//Navigation Properties
public Offer Offer { get; }
}

Related

EF Code first, table relationship problem

I get an error in the comments model in relations, I'm waiting for a practical answer, it seems like there is nothing difficult. I use the picture model easily in the article model. I thought of using this table in the auhor model, but I am stuck in relationships, what should I do?
public class Article
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Detail { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public bool IsActive { get; set; } = false;
// Scaler properties
public int AuthorId { get; set; }
public int CategoryId { get; set; }
// Navigation properties
public virtual Picture Picture { get; set; } = new Picture();
public virtual Author Author { get; set; } = new Author();
public virtual Category Category { get; set; } = new Category();
public virtual ICollection<Comment>? Comments { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Surname { get; set; } = string.Empty;
public string EMail { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public DateTime DateOfBirth { get; set; }
public DateTime CreatedAt { get; set; }
// Navigation properties
public virtual ICollection<Article>? Articles { get; set; }
public virtual ICollection<Comment>? Comments { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public byte SortBy { get; set; }
// Navigation property
public virtual ICollection<Article>? Articles { get; set; }
}
public class Comment
{
public int Id { get; set; }
public string Content { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public bool IsActive { get; set; } = false;
// Scaler properties
public int ArticleId { get; set; }
public int AuthorId { get; set; }
// Navigation properties
public virtual Article Article { get; set; } = new Article();
public virtual Author Author { get; set; } = new Author();
}
public class Picture
{
public int Id { get; set; }
public string Src { get; set; } = string.Empty;
public string Alt { get; set; } = string.Empty;
public string? Title { get; set; }
// Scaler property
public int ArticleId { get; set; }
// Navigation property
public virtual Article Article { get; set; } = new Article();
}
This is the error:
Introducing FOREIGN KEY constraint 'FK_Comments_Authors_AuthorId' on
table 'Comments' may cause cycles or multiple cascade paths. Specify
ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN
KEY constraints. Could not create constraint or index. See previous
errors
Are there any problems in other relationships? we can discuss

How to create a relation between existing entities in EF core?

I have a case scenario with two tables References and Products alreading containing many entries which can be dynamically related on demand.
public class Reference
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ReferenceId { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public virtual ICollection<Product> ManyProducts { get; set; }
public Reference() {}
}
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
[ForeignKey("Reference")]
public Guid ReferenceId { get; set; }
public virtual Reference OneReference { get; set; }
public Product() {}
}
When a user ask to link a reference to a product I simply do :
product.ReferenceId = reference.ReferenceId ;
await context.SaveChangesAsync() ;
The entry in Products table is updated correctly, but when I try to access a reference's related data, it does not retrieve any ?? After eager loading :
var reference = await context.References
.Include(r => r.ManyProducts)
.SingleAsync(r => r.ReferenceId == referenceId) ;
or explicit loading :
var reference = await context.References.FindAsync(referenceId) ;
await context.Entry(reference).Collection(s => s.ManyProducts).LoadAsync() ;
reference.ManyProducts is empty. So I have to do something like this :
var reference = await context.References.FindAsync(referenceId) ;
var products = await context.Products.Where(l => l.ReferenceId == referenceId).ToListAsync() ;
result.ManyProducts = products ;
which works fine, but I would like to understand why ?
I´m using DataAnnotation
Sample
public class spread
{
[Key]
public int spreadid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange origem")]
public virtual exchange exchange { get; set; } // One to one
[ForeignKey("spreadid")]
public virtual ICollection<spreadhelper> spreadhelper { get; set; } // One to many
}
public class spreadhelper
{
[Key]
public int spreadhelperid { get; set; }
[Required]
public int spreadid { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange")] // One to one
public virtual exchange exchange { get; set; }
[Required, Range(0, 200)]
public decimal spreadvalue { get; set; }
}
one to one - sample
public class exchange
{
[Key]
public int exchangeid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required, MaxLength(50)]
public string name { get; set; }
[MaxLength(128)]
public string token { get; set; }
}
One to many sample

Automapper nested mapping 3 levels

i have the following problem, i need access to items of sales line from salesheader, when i try access by entity works fine by lazy loading, but i try map with Automapper 6
can´t access to Item from sales header
thanks
public class SalesHeader
{
public int DocumentNo { get; set; }
public virtual ICollection<PostedSalesLine> SalesLines { get; set; }
}
public class SalesLine
{
public int LineNo { get; set; }
public int DocumentNo { get; set; }
public int ItemId { get; set; }
public virtual Item Item { get; set; }
public int Quantity { get; set; }
public decimal Amount { get; set; }
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public decimal UnitCost { get; set; }
public decimal UnitPrice { get; set; }
}
var result = unitOfWork.SalesHeader.GetById(documenNo);
Mapper.Initialize(cfg => cfg.CreateMap<SalesHeader, SalesHeaderDTO>()
return Mapper.Map<SalesHeaderDTO>(result);
Done!
Dont use lazy loading, it creates a mess of proxys
public IEnumerable<SalesHeader> GetAllFullDocuments()
{
return SalesContext.SalesHeader.Include(sh => sh.SalesLines.Select(i => i.Item))
.Include(sh => sh.SellToCustomer)
.Include(sh => sh.BillToCustomer)
.ToList();
}

multiple navigation properties to the same table using code first

I have a one-to-many relationship setup. IT is working fine but now I am trying to use pdfsharp and I need some help with the navigation properties. Every Measurement has 4 pictures. Front, Back, Right, Left. I need to include all 4 pics in the pdf. I am unable to reach them with what i have now. I can return the list of pictures per measurement in a table. Just dont know how to change it for this to work as well.
public class Measurement
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public DateTime? MeasurementDate { get; set; }
public decimal? BustMeasurement { get; set; }
public decimal? ChestMeasurement { get; set; }
public decimal? FAT { get; set; }
public string MeasurementUploadBy { get; set; }
public DateTime? MeasurementUploadDate { get; set; }
public DateTime? MeasurementEditDate { get; set; }
public string MeasurementEditBy { get; set; }
public int? ClientId { get; set; }
[ForeignKey("ClientId")]
public virtual Client Client { get; set; }
public virtual ICollection<Picture> Pictures { get; set; }
}
public class Picture
{
public int Id { get; set; }
public string PictureFrontUrl { get; set; }
public string PictureBackUrl { get; set; }
public string PictureRightSideUrl { get; set; }
public string PictureLeftSideUrl { get; set; }
public string PictureNote { get; set; }
public string PictureUploadBy { get; set; }
public DateTime? PictureUploadDate { get; set; }
public DateTime? PictureDate { get; set; }
public string ClientName { get; set; }
public string PictureType { get; set; }
public Guid MeasurementId { get; set; }
[ForeignKey("MeasurementId")]
public virtual Measurement Measurement { get; set; }
}
MeasurementApi
public Measurement GetMeasurement(Guid id)
{
using (var context = new ApplicationDbContext())
{
Measurement model = new Measurement();
model = context.Measurements
.Include(x => x.Pictures)
.FirstOrDefault(j => j.Id == id);
return model;
}
}
PDFSharp GEt Call
apiMeasurementController adapter = new apiMeasurementController();
Measurement model = new Measurement();
model = adapter.GetMeasurement(id);
If you want your Measurement to have 4 pictures, and not a colleciton of pictures you should have something like this:
public class Measurement
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
....
// Won't need these
// public virtual ICollection<Picture> Pictures { get; set; }
public virtual Picture LeftPicture { get; set; }
public virtual Picture TopPicture { get; set; }
public virtual Picture RightPicture { get; set; }
public virtual Picture BottomPicture { get; set; }
}
And your picture:
public class Picture
{
public int Id { get; set; }
// Don't need these 4 any more.
// public string PictureFrontUrl { get; set; }
// public string PictureBackUrl { get; set; }
// public string PictureRightSideUrl { get; set; }
// public string PictureLeftSideUrl { get; set; }
public string PictureUrl { get; set; }
public string PictureNote { get; set; }
public string PictureUploadBy { get; set; }
public DateTime? PictureUploadDate { get; set; }
public DateTime? PictureDate { get; set; }
public string ClientName { get; set; }
public string PictureType { get; set; }
public Guid MeasurementId { get; set; }
[ForeignKey("MeasurementId")]
public virtual Measurement Measurement { get; set; }
}
And in your API
public Measurement GetMeasurement(Guid id)
{
using (var context = new ApplicationDbContext())
{
Measurement model = new Measurement();
model = context.Measurements
.Include(x => x.LeftPicture)
.Include(x => x.TopPicture)
.Include(x => x.RightPicture)
.Include(x => x.BottomPicture)
.FirstOrDefault(j => j.Id == id);
return model;
}
}

Entity Framework navigation property

I'm trying to use EF to get data from my database. I have a table Interventions that has a Client associated with it like this:
public partial class Client
{
public Client()
{
this.Interventions = new List<Intervention>();
}
public int client_id { get; set; }
public string full_name { get; set; }
public string cgroup { get; set; }
public string nation { get; set; }
public virtual ICollection<Intervention> Interventions { get; set; }
}
public partial class Intervention
{
public int intervention_id { get; set; }
public int technician_id { get; set; }
public int client_id { get; set; }
public string type { get; set; }
public int done { get; set; }
public int year { get; set; }
public int month { get; set; }
public int week { get; set; }
public Nullable<int> avg_response_time { get; set; }
public int number_of_equip { get; set; }
public virtual Client Client { get; set; }
public virtual Technician Technician { get; set; }
}
I can get a list of interventions by doing this:
public object Any(GetInterventions request)
{
List<Intervention> dbItems;
using (var context = new operationsContext())
{
context.Configuration.LazyLoadingEnabled = false;
dbItems = context.Interventions.ToList();
return new GetInterventionsResponse{
interventions = dbItems
};
}
}
Although, when I try to retrieve the client associated with each intervention
dbItems = context.Interventions.Include("Client").ToList();
by including a Client navigation property I get a Visual Studio a stackOverflowException.
Am I doing anything wrong using EF or is just a question of general bad programming?
thanks in advance
The problem was solved by introducing decorations of [DataContract] and [DataMember] on the classes and fields that I wanted to serialize on the JSON response. Just like the example below:
using System.Runtime.Serialization;
namespace OperationsAPI.Models
{
[DataContract]
public partial class Intervention
{
public int intervention_id { get; set; }
public int technician_id { get; set; }
public int client_id { get; set; }
public string type { get; set; }
public int done { get; set; }
public int year { get; set; }
[DataMember]
public int month { get; set; }
[DataMember]
public int week { get; set; }
[DataMember]
public Nullable<int> avg_response_time { get; set; }
public int number_of_equip { get; set; }
[DataMember]
public virtual Client Client { get; set; }
public virtual Technician Technician { get; set; }
}
}

Categories