I have belowe Classes:
1- PurchaseMaster :Has collection >> PurchaseDetail
2- PurchaseDetail :Has Product
3- Product
I want get PurchaseMaster with Detail and Product . I try with belowe queries but Its return error :
var purchaseMasterModel = _purchaseMasters
.Include("StoreMasters.Details")
.Include("ProductHeader")
.FirstOrDefault(row => row.Code == code);
var purchaseMasterModel = _purchaseMasters
.Include("StoreMasters.Details")
.Include("StoreMasters.Details.ProductHeader")
.FirstOrDefault(row => row.Code == code);
var purchaseMasterModel = _purchaseMasters
.Include("StoreMasters.Details")
.Include("Details.ProductHeader")
.FirstOrDefault(row => row.Code == code);
I getting this errors:
A specified Include path is not valid. The EntityType 'DataLayer.Context.StoreDetail' does not declare a navigation property with the name 'ProductHeader'.
my classes like this :
public class PurchaseMaster:BaseEntity
{
public virtual ICollection<PurchaseDetail> PurchaseDetails { get; set; }
}
public class PurchaseDetail:BaseEntity
{
public PurchaseMaster PurchaseMaster { get; set; }
public Guid PurchaseMasterId { get; set; }
public ProductHeader ProductHeader { get; set; }
public Guid ProductHeaderId { get; set; }
}
public class ProductHeader:BaseEntity
{
public virtual ICollection<PurchaseDetail> PurchaseDetails { get; set; }
}
You are already selecting PurchaseMaster, so you should not specify StoreMaster.
You also have to use the property names. ProductHeader has a property PurchaseDetails, but not Details.
The following query should work:
var purchaseMasterModel = _purchaseMasters
.Include("PurchaseDetails")
.Include("PurchaseDetails.ProductHeader")
.FirstOrDefault(row => row.Code == code);
Related
Ok this one is confusing me. I'm trying to return objects with included linked objects, but it fails when I use a dto:
class MyObject1
{
public int Id { get; set; }
[Required]
public MyObject2 Mo2 { get; set }
//Other properties
}
class MyObject2
{
public int Id { get; set; }
//Other properties
}
class MyObject3
{
public int Id { get; set; }
public int MyIntValue { get; set; }
//Other properties
}
class MyDTO
{
public MyObject1 Mo1 { get; set; }
public int MyIntValue { get; set; }
}
When I use the anonymous selector, i get the linked objects loaded:
void ThisWorks()
{
var result = await
(
from mo1 in context.MyObject1s
.Include(item => item.Mo2)
//No nav-path or foriegn key setup, so do it the old fashioned way
join mo3 in context.MyObject3s on mo1.Id equals mo3.Id into mo3s
from mo3 in mo3s.DefaultIfEmpty()
select new
{
mo1,
myIntValue = mo3 == null ? 0 : mo3.MyIntValue
}
)
.ToListAsync();
bool success = result.Mo1.Mo2 != null;
//result.Mo1.Mo2 is not null!
}
But when I try to use the Dto, it fails:
void ThisFails()
{
var result = await
(
from mo1 in context.MyObject1s
.Include(item => item.Mo2)
//No nav-path or foriegn key setup, so do it the old fashioned way
join mo3 in context.MyObject3s on mo1.Id equals mo3.Id into mo3s
from mo3 in mo3s.DefaultIfEmpty()
select new MyDto
{
Mo1 = mo1,
MyIntValue = mo3 == null ? 0 : mo3.MyIntValue
}
)
.ToListAsync();
bool success = result.Mo1.Mo2 != null;
//result.Mo1.Mo2 is null - Why? And how do I solve it?
}
Why does the linked object not load when I create a Dto? I'm using the query in a few different places, so I want to define it once, but I need a dto to hold the MyIntValue. Is there a way to do this?
Include has no effect on projections.
You must create a separate property to hold the child entity:
class MyDTO
{
public MyObject1 Mo1 { get; set; }
public MyObject2 Mo2 { get; set; }
public int MyIntValue { get; set; }
}
and project like this:
select new MyDto
{
Mo1 = mo1,
Mo2 = mo1.Mo2,
MyIntValue = mo3 == null ? 0 : mo3.MyIntValue
}
I would suggest to not hold entities inside your DTOs. Would be better to flatten the values, or create "child DTOs" (like Dto1 and Dto2 for each entity).
So I've got a nested data structure like this:
public class ContractTerm
{
public int ContractId { get; set; }
public string SectionId { get; set; }
public string SubsectionId { get; set; }
public string TermId { get; set; }
public int TermOrder { get; set; }
public TermItem TermNavigation { get; set; }
}
public class TermItem
{
public string SectionId { get; set; }
public string SubsectionId { get; set; }
public string TermId { get; set; }
public string Text { get; set; }
public ICollection<ContractTerm> ContractNavigation { get; set; }
}
I've also got a class to map the section/subsection pairings in a more EF-friendly way (IRL this is an enum with attribute values and a helper, but this class abstracts away some work not necessary to reproduce the issue):
public class Section
{
public string Name { get; set; }
public string SectionId { get; set; }
public string SubsectionId { get; set; }
}
Both ContractTerm and TermItem have their own collections in a DbContext, and I'm trying to get a collection of all text entries assigned to specific Sections for a given ContractId. I have the following class to contain it:
public class TextsBySection
{
public string SectionName { get; set; }
public IEnumerable<string> Texts { get; set; }
}
I want to select a collection of TextsBySection, and have something like this:
public class ContractManager
{
//insert constructor initializing MyContext here
private MyContext Context { get; }
public IEnumerable<MyOutputClass> GetTerms(int contractId, IEnumerable<Section> sections)
{
Func<string, string, IEnumerable<string>> getBySection =
(section, subsection) => context.ContractTerms.Include(x => x.TermNavigation)
.Where(x => x.ContractId == contractId
&& x.SectionId == section
&& x.SubsectionId == subsection)
.Select(x => x.TermNavigation.Text);
var result = sections.Select(x => new MyOutputClass
{
SectionName = x.Name,
Texts = getBySection(x.SectionId, x.SubsectionId)
}).ToList();
return result;
}
}
This works fine and dandy, but it hits the database for every Section. I feel like there's got to be a way to use Join and/or GroupBy to make it only query once, but I can't quite see it. Something like this, perhaps:
var result = context.ContractTerms.Include(x => x.TermNavigation)
.Where(x => x.ContractId == contractId)
.Join(sections,
term => //something
section => //something
(term, section) => /*something*/)
If all this were in SQL, selecting the necessary data would be easy:
SELECT sections.name,
term_items.text
FROM contract_terms
JOIN term_items
ON term_items.section_id = contract_terms.section_id
AND term_items.subsection_id = contract_terms.subsection_id
AND term_items.term_id = contract_terms.term_id
JOIN sections --not a real table; just corresponds to sections argument in method
ON sections.section_id = contract_terms.section_id
AND sections.subsection_id = contract_terms.subsection_id
...and then I could group the results in .NET. But I don't understand how to make a single LINQ query that would do the same thing.
I changed my answer, well I would do something like this... maybe this may help you.
public static void Main(string[] args)
{
List<Section> sections = new List<Section>();
List<ContractTerm> contractTerms = new List<ContractTerm>();
List<TermItem> termItens = new List<TermItem>();
//considering lists have records
List<TextsBySection> result = (from contractTerm in contractTerms
join termItem in termItens
on new
{
contractTerm.SectionId,
contractTerm.SubsectionId,
contractTerm.TermId
}
equals new
{
termItem.SectionId,
termItem.SubsectionId,
termItem.TermId
}
join section in sections
on new
{
contractTerm.SectionId,
contractTerm.SubsectionId
} equals new
{
section.SectionId,
section.SubsectionId
}
select
new
{
sectionName = section.Name,
termItemText = termItem.Text
}).GroupBy(x => x.sectionName).Select(x => new TextsBySection()
{
SectionName = x.Key,
Texts = x.Select(i=> i.termItemText)
}).ToList();
}
Multiple answers have led me to the following 2 solutions, but both of them do not seem to be working correctly.
What I have are 2 objects
public class DatabaseAssignment : AuditableEntity
{
public Guid Id { get; set; }
public string User_Id { get; set; }
public Guid Database_Id { get; set; }
}
public class Database : AuditableEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Server { get; set; }
public bool IsActive { get; set; }
public Guid DatabaseClientId { get; set; }
}
Now, the front-end will return all selected Database objects (as IEnumerable) for a given user. I am grabbing all current DatabaseAssignments from the database for the given user and comparing them to the databases by the Database.ID property. My goal is to find the DatabaseAssignments that I can remove from the database. However, my solutions keep returning all DatabaseAssignments to be removed.
if (databases != null)
{
var unitOfWork = new UnitOfWork(_context);
var userDatabaseAssignments = unitOfWork.DatabaseAssignments.GetAll().Where(d => d.User_Id == user.Id);
//var assignmentsToRemove = userDatabaseAssignments.Where(ud => databases.Any(d => d.Id != ud.Database_Id));
var assignmentsToRemove = userDatabaseAssignments.Select(ud => userDatabaseAssignments.FirstOrDefault()).Where(d1 => databases.All(d2 => d2.Id != d1.Database_Id));
var assignmentsToAdd = databases.Select(d => new DatabaseAssignment { User_Id = user.Id, Database_Id = d.Id }).Where(ar => assignmentsToRemove.All(a => a.Database_Id != ar.Database_Id));
if (assignmentsToRemove.Any())
{
unitOfWork.DatabaseAssignments.RemoveRange(assignmentsToRemove);
}
if (assignmentsToAdd.Any())
{
unitOfWork.DatabaseAssignments.AddRange(assignmentsToAdd);
}
unitOfWork.SaveChanges();
}
I think u are looking for an Except extension, have a look at this link
LINQ: Select where object does not contain items from list
Or other way is with contains see below Fiddler link :
https://dotnetfiddle.net/lKyI2F
Entities:
public class Entity
{
public int Id { get; set; }
}
public class User : Entity
{
public string Name { get; set; }
public Company Company { get; set; }
}
public class Company : Entity
{
public string Name { get; set; }
}
Dto's:
public class EntityDto
{
public int Id { get; set; }
}
public class UserDto : EntityDto
{
public string Name { get; set; }
public int? CompanyId { get; set; }
}
So I want to map User to UserDto like User.Company == null => UserDto.CompanyId == null and vice versa.
That is my Automapper configuration:
Mapper.Initialize(configuration =>
{
configuration
.CreateMap<User, UserDto>()
.ReverseMap();
});
This works fine:
[Fact]
public void UnattachedUserMapTest()
{
// Arrange
var user = new User { Company = null };
// Act
var userDto = Mapper.Map<User, UserDto>(user);
// Assert
userDto.CompanyId.Should().BeNull();
}
but this test fails:
[Fact]
public void UnattachedUserDtoMapTest()
{
// Arrange
var userDto = new UserDto { CompanyId = null };
// Act
var user = Mapper.Map<UserDto, User>(userDto);
// Assert
user.Company.Should().BeNull();
}
Details:
Expected object to be <null>, but found
Company
{
Id = 0
Name = <null>
}
Doesn't work for me:
...
.ReverseMap()
.ForMember(user => user.Company, opt => opt.Condition(dto => dto.CompanyId != null));
and well as that (just for example):
...
.ReverseMap()
.ForMember(user => user.Company, opt => opt.Ignore());
Why does Automapper create nested object and how can I prevent it?
That "suddenly" bit is funny :)
configuration.CreateMap<User, UserDto>().ReverseMap().ForPath(c=>c.Company.Id, o=>o.Ignore());
You have a default MapFrom with CompanyId and that is applied in reverse. For details see this and a few other similar issues.
In the next version (on MyGet at the moment) you'll also be able to use
configuration.CreateMap<User, UserDto>().ReverseMap().ForMember(c=>c.Company, o=>o.Ignore());
The following are the entity classes to make more understanding of relationships:
public class EmployeeCv : UserEntity
{
public byte ProfileImage { get; set; }
public virtual List<Header> Headers { get; set; }
public virtual List<ProjectExperience> ProjectExperiences { get; set; }
public virtual List<Tag> Tags { get; set; } //many to many relationship between employeeCv and tags
[NotMapped]
public List<TagsByTypes> TagsbyTypes
{
get
{
List<TagsByTypes> ListOfTagTypes = new List<TagsByTypes>();
if (Tags != null)
{
var GroupedList = Tags.GroupBy(x => x.TagType.Title).ToList().Select(grp => grp.ToList());
foreach (var currentItem in GroupedList)
{
var TagType = new TagsByTypes()
{
Title = currentItem.FirstOrDefault().TagType.Title,
Tags = currentItem
};
ListOfTagTypes.Add(TagType);
}
return ListOfTagTypes;
}
else
return null;
}
}
}
public class Tag : AuditableEntity<int>
{
public string Title { get; set; }
public virtual List<EmployeeCv> EmployeeCv { get; set; }
public virtual TagType TagType { get; set; }
//To post Id's Not added to the database
[NotMapped]
public int TagTypeId { get; set; }
[NotMapped]
public int EmployeeCv_Id { get; set; }
}
public class TagType : AuditableEntity<int>
{
public string Title { get; set; }
public virtual List<Tag> Tags { get; set; }
}
I am writing a function to add new tag to the employeeCv based on the existing tag type. I have got Unit of work and Repositories setup to add/update/delete records in DB. Here is my implementation:
public void UpdateEmployeeCVWithTag(Tag tag)
{
using (var repository = new UnitOfWork<EmployeeCv>().Repository)
{
var EmployeeCv = repository.GetSingleIncluding(tag.EmployeeCv_Id,
x => x.Headers, x => x.Tags,
x => x.ProjectExperiences,
x => x.ProjectExperiences.Select(p => p.AssociatedProject),
x => x.ProjectExperiences.Select(p => p.ProjectSkills));
//x => x.ProjectExperiences.Select(p => p.ProjectSkillTags.Select(s => s.AssociatedSkill)));
//tag.TagType = EmployeeCv;
var repositoryTagType = new UnitOfWork<TagType>().Repository;
var tagtype = repositoryTagType.GetItemById(tag.TagTypeId);
tag.TagType = tagtype; //even after assignment new tagtype is creating everytime code runs
//repositoryTag.UpdateItem(tagtype);
EmployeeCv.Tags.Add(tag);
//EmployeeCv.ProjectExperiences[projectId - 1].ProjectSkills.Add(tag);
repository.UpdateItem(EmployeeCv);
}
}
This function works correctly except one issue. It is creating a new TagType in the database and ignoring the one that already exist. Below is my updateItem code in the repository classs:
public virtual void UpdateItem(TEntity entityToUpdate)
{
var auditableEntity = entityToUpdate as IAuditableEntity;
if (auditableEntity != null)
{
auditableEntity.UpdatedDate = DateTime.Now;
}
//_context
//Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
_context.SaveChanges();
}
My guess without seeing the full functionality, is that you are using different context for this.
You should update the foreign key not the entire object so there is no need to add the entire TagType object since the tagTypeId is already set. The foreign key should work as is.
Please look into this link for further information.