Using Automapper CreateMap to concatenate elements - entity-framework

I have the following EF classes:
public class Request
{
[Key]
public virtual int RequestID { get; set; }
...
public virtual List<RequestLinked> RequestLinkeds { get; set; }
}
public class RequestLinked
{
[Key, Column(Order = 0)]
[ForeignKey("Request")]
public int RequestID { get; set; }
[Key, Column(Order = 1)]
[ForeignKey("RequestRelated")]
public int RequestRelatedID { get; set; }
public virtual Request Request { get; set; }
public virtual Request RequestRelated { get; set; }
}
I created a DTO like this:
[DataContract]
public class RequestDTO
{
[DataMember]
public int RequestID { get; set; }
...
[DataMember]
public string RequestRelatedIDs { get; set; }
}
Now I would like to use automapper fo fill my DTO object. I need to fill RequestRelatedIDs with all elements from RequestLinkeds.RequestRelatedID by concatenate all elements inside 1 string.
I tried this:
CreateMap<Request, RequestDTO>()
.ForMember(x => x.RequestRelatedIDs, o => o.MapFrom(src => string.Join(", ", src.RequestLinkeds.Select(x => x.RequestRelatedID));
But the Select method is red highlighted: System.Collections.Generic.List< PLATON.Domain.Models.RequestLinked >' does not contain a definition for 'Select'
Why is that not possible to perform a select? An alternative?
Thanks.

Related

How can I order by many-to-many extra column in Entity Framework Core?

I am using Entity Framework Core 3. Member and Request entities are related many-to-many. But I have an extra column named Order. The member request order is saved in the MemberRequest table.
public class Member
{
public int MemberID { get; set; }
public string Name { get; set; }
public virtual ICollection<MemberRequest> MemberRequests { get; set; }
}
public class Request
{
public int RequestID { get; set; }
public string Message { get; set; }
public virtual ICollection<MemberRequest> MemberRequests { get; set; }
}
public class MemberRequest
{
[Key, Column(Order = 0)]
public int MemberID { get; set; }
[Key, Column(Order = 1)]
public int RequestID { get; set; }
public virtual Member Member { get; set; }
public virtual Request Request { get; set; }
public int Order { get; set; }
}
I want to get two select using Entity Framework Core:
public IEnumerable<Member> Get(int id)
{
var members = await _context.Request
.Include(e => e.MemberRequests)
.Where(e => e.MemberRequests.Any(m => m.RequestID == id))
.ToListAsync();
// How can I order by MemberRequest.Order ???
return member;
}
But I could not order result by MemberRequest.Order in MemberRequest entity. How can I do it?

independent association between two non-relational / unrelated entities

I have a need to obtain a list of non-relational entity values using a navigational property. In the following model for FVariable, I am trying to create a navigation property for maintaining a list of VariableValue. How to define an independent association as depicted in the model of FVariable:
public virtual ICollection<VariableValue> Values { get; set; } ?
The two entities are related through VariableID and DataAttributeCollectionID properties.
Here is the FVariable Entity:
public class FVariable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int FVariableID { get; set; }
[Index(Unique, Order = 1)]
public int VariableID { get; set; }
[ForeignKey(nameof(F.VariableID))]
public virtual Variable Variable { get; set; }
[Index(Unique, IsUnique = true, Order = 2)]
public int? DataAttributeCollectionID { get; set; }
[ForeignKey(nameof(FVariable.DataAttributeCollectionID))]
public virtual DataAttributeCollection DataAttributeCollection { get; set; }
public virtual ICollection<VariableValue> Values { get; set; }
}
Here is the VariableValue entity:
public class VariableValue
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int VariableValueID { get; set; }
[Index(Order = 1)]
public int VariableID { get; set; }
[ForeignKey(nameof(VariableValue.VariableID))]
public virtual Variable Variable { get; set; }
[Index(Order = 2)]
public double VariableValue { get; set; }
public int? DataAttributeCollectionID { get; set; }
[ForeignKey(nameof(VariableValue.DataAttributeCollectionID))]
public virtual DataAttributeCollection DataAttributeCollection { get; set; }
}

How do I get a response based on two different IDs in my API?

public class Report
{
[Key]
public int ReportId { get; set; }
[ForeignKey("Subjects")]
public int SubjectId { get; set; }
public Subjects Subjects { get; set; }
[ForeignKey("Teacher")]
public int TeacherId { get; set; }
public Teacher Teacher { get; set; }
[ForeignKey("MarkType")]
public int MarkTypeId { get; set; }
public MarkType MarkType { get; set; }
}
public class Teacher
{
[Key]
public int TeacherId { get; set; }
[MaxLength(50)]
[Required]
public string FName { get; set; }
[MaxLength(50)]
[Required]
public string LName { get; set; }
}
public class Student
{
[Key]
public int StudentId { get; set; }
[MaxLength(50)]
[Required]
public string FName { get; set; }
[MaxLength(50)]
[Required]
public string LName { get; set; }
[ForeignKey("Grade")]
public int GradeId { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
[Key]
public int GradeId { get; set; }
public int StudentGrade { get; set; }
}
public class Subjects
{
[Key]
public int SubjectId { get; set; }
[MaxLength(50)]
[Required]
public string SubjectName { get; set; }
}
public class Terms
{
[Key]
public int TermId { get; set; }
public int Term { get; set; }
}
public class MarkType
{
[Key]
public int MarkTypeId { get; set; }
[MaxLength(20)]
[Required]
public string TypeName { get; set; }
}
public class StudentMark
{
[Key]
public int StudentMarkId { get; set; }
[ForeignKey("Report")]
public int ReportId { get; set; }
public Report Report { get; set; }
[ForeignKey("Student")]
public int StudentId { get; set; }
public Student Student { get; set; }
public int Mark { get; set; }
[ForeignKey("Terms")]
public int TermId { get; set; }
public Terms Terms { get; set; }
}
In the API I am making I want to have the ability to use two different IDs to get a more specific response.
var report = ReportDBContext.StudentMark
.Include(p => p.Student.Grade).Include(p => p.Report)
.Include(p => p.Terms).Include(a => a.Report.Subjects).Include(a => a.Terms)
.Include(a => a.Report.MarkType).Include(a => a.Report.Teacher).ToList();
This allowed me to get StudentMark as well as it's related entities but I want to have the ability to use The student's Id and the Term's Id to get a student's marks for that term and all the subjects related to the student. I am a beginner to Web API so please let me know if I need to add more context.
If you want to query by either StudentId or TermId, I suggest that you provide two different endpoints for these two different queries. Use LINQ Where to check your conditions.
public StudentMark[] GetMarksByStudentId(int studentId) {
return ReportDBContext.StudentMark
/* .Include(...) */
.Where(mark => mark.StudentId == studentId)
.ToArray();
}
public StudentMark[] GetMarksByTermId(int termId) {
return ReportDBContext.StudentMark
/* .Include(...) */
.Where(mark => mark.TermId == termId)
.ToArray();
}
If you want to query by StudentId and TermId simultaneously, introduce a query object to encapsulate your parameters. You can test for multiple conditions in the Where clause with AND &&.
public StudentMark[] FindMarks(StudentMarkQuery query) {
return ReportDBContext.StudentMark
/* .Include(...) */
.Where(mark => mark.StudentId == query.StudentId
&& mark.TermId == query.TermId)
.ToArray();
}
The StudentMarkQuery class is introduced so you can add additional parameters without changing the overall signature of the endpoint:
public class StudentMarkQuery {
public int StudentId { get; set; }
public int TermId { get; set; }
}

Alternative to List.Include in EF

I am having circular reference due to the EF code below. I have a Parent table with 2 childs and their grandchildren respectively. Is there any alternative to using Include, as I read something about Navigation property and it includes the parents in each of the child, causing the serialization having circular reference problem.
Error Message:
A circular reference was detected while serializing an object of type 'Product'.
This part is only to get retrieval and I don't need the parent reference back to each of the child. I debug inside and saw that inside each of the child, it has the parent reference back.
var query = db.Products.Include(c => c.ProductTriggers.Select(b => b.ProductTriggerItems))
.Include(d => d.ProductsExtra.Select(e => e.ProductAllotments.Select(m => m.ProductAllotmentDetails))).AsNoTracking();
return query.ToList();
Product Class
public partial class Product
{
public Product()
{
this.ProductExtras = new HashSet<ProductExtra>();
this.ProductTriggers = new HashSet<ProductTrigger>();
}
public int ProductID { get; set; }
public string ProductCode { get; set; }
public string ProductName { get; set; }
public virtual ICollection<ProductProduct> ProductExtras { get; set; }
public virtual ICollection<ProductTrigger> ProductTriggers { get; set; }
}
ProductExtra Class
public partial class ProductExtra
{
public ProductExtra()
{
this.ProductAllotments = new HashSet<ProductAllotment>();
}
public int ProductExtraID { get; set; }
public int ProductID { get; set; }
public virtual Product Product { get; set; }
public virtual ICollection<ProductAllotment> ProductAllotments { get; set; }
}
ProductAllotment Class
public partial class ProductAllotment
{
public ProductAllotment()
{
this.ProductAllotmentDetails = new HashSet<ProductAllotmentDetail>();
}
public int ProductAllotmentID { get; set; }
public int ProductExtraID { get; set; }
public virtual ProductExtra ProductExtra { get; set; }
public virtual ICollection<ProductAllotmentDetail> ProductAllotmentDetails { get; set; }
}
ProductTrigger Class
public partial class ProductTrigger
{
public ProductTrigger()
{
this.AddOnTriggerItems = new HashSet<ProductTriggerItem>();
}
public int ProductTriggerID { get; set; }
public int ProductID { get; set; }
public virtual Product Product { get; set; }
public virtual ICollection<ProductTriggerItem> ProductTriggerItems { get; set; }
}
ProductTriggerItem Class
public partial class ProductTriggerItem
{
public int ProductTriggerItemID { get; set; }
public int ProductTriggerID { get; set; }
public virtual ProductTrigger ProductTrigger { get; set; }
}

Entity Framework, configuration for reading and writing

Given the following database model
I have two fluent entity framework configurations, one that works when I read (the setupFields list is set) and the other for writing, which if I use for reading as well, always comes with an empty SetupFields list
[Table("[BALANCE.SETUP]")]
public class SetupEntity
{
[Key]
public Guid Id { get; set; }
public string Title { get; set; }
public virtual ChassisEntity Chassis { get; set; }
public virtual EventEntity Event { get; set; }
public virtual ICollection<SetupFieldEntity> SetupFields { get; set; }
}
[Table("[BALANCE.SETUP.FIELD]")]
public class SetupFieldEntity
{
[Key]
[Column(Order = 0)]
public Guid SetupId { get; set; }
[Key]
[Column(Order = 1)]
public int Sequence { get; set; }
public string Section { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual SetupEntity Setup { get; set; }
}
(can read)
modelBuilder.Entity<SetupEntity>()
.HasMany(x => x.SetupFields)
.WithRequired(x => x.Setup)
.Map(x => x.MapKey("SETUPID"));
(can write)
modelBuilder.Entity<SetupEntity>()
.HasMany(x => x.SetupFields)
.WithRequired()
.HasForeignKey(x => x.SetupId);
If I use the read configuration to read, this is the error I get:
The column name 'SETUPID' is specified more than once in the SET clause. A column cannot be assigned more than one value in the same SET clause. Modify the SET clause to make sure that a column is updated only once. If the SET clause updates columns of a view, then the column name 'SETUPID' may appear twice in the view definition.
UPDATE 1
Just to make things clear, the models are lazy loaded and I'm explicitly inclucing them, so, when using the first connfiguration the models are set as expected:
if (includeFields)
{
x = x.Include(entity => entity.SetupFields);
}
UPDATE 2
Based on the comments bellow I change the mappings to have just this which works when inserting but when reading the child collection is still null:
modelBuilder.Entity<SetupEntity>().HasMany(x => x.SetupFields);
[Table("[BALANCE.SETUP]")]
public class SetupEntity
{
[Key]
public Guid Id { get; set; }
public string Title { get; set; }
public virtual ChassisEntity Chassis { get; set; }
public virtual EventEntity Event { get; set; }
public virtual ICollection<SetupFieldEntity> SetupFields { get; set; }
}
[Table("[BALANCE.SETUP.FIELD]")]
public class SetupFieldEntity
{
[Key]
[Column(Order = 0)]
public Guid SetupId { get; set; }
[Key]
[Column(Order = 1)]
public int Sequence { get; set; }
public string Section { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual SetupEntity Setup { get; set; }
}
UPDATE 3
Based on the comments I completelly removed the attributes from the entities, but the collection property is still null :(
public class SetupEntity
{
public Guid Id { get; set; }
public string Title { get; set; }
public virtual ChassisEntity Chassis { get; set; }
public virtual EventEntity Event { get; set; }
public virtual ICollection<SetupFieldEntity> SetupFields { get; set; }
}
[Table("[BALANCE.SETUP.FIELD]")]
public class SetupFieldEntity
{
public Guid SetupId { get; set; }
public int Sequence { get; set; }
public string Section { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual SetupEntity Setup { get; set; }
}
modelBuilder.Entity<SetupEntity>()
.HasKey(x => x.Id)
.HasMany(x => x.SetupFields)
.WithRequired(x => x.Setup);
modelBuilder.Entity<SetupFieldEntity>()
.HasKey(x => x.SetupId)
.HasKey(x => x.Sequence);