엔티티 프레임 워크에 의해 생성되는 product라는 엔티티 유형이 있습니다. 이 쿼리를 작성했습니다
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products
where p.CategoryID== categoryID
select new Product { Name = p.Name};
}
아래 코드는 다음 오류를 발생시킵니다.
“엔터티 또는 복합 유형 Shop.Product는 LINQ to Entities 쿼리에서 구성 할 수 없습니다.”
var products = productRepository.GetProducts(1).Tolist();
그러나 select p
대신 대신 사용하면 select new Product { Name = p.Name};
올바르게 작동합니다.
맞춤 선택 섹션을 미리 수행하려면 어떻게해야합니까?
답변
매핑 된 엔터티에 프로젝트를 투사 할 수 없으며 사용할 수 없어야합니다. 그러나 익명 형식이나 DTO 에 투영 할 수 있습니다 .
public class ProductDTO
{
public string Name { get; set; }
// Other field you may need from the Product entity
}
그리고 귀하의 방법은 DTO 목록을 반환합니다.
public List<ProductDTO> GetProducts(int categoryID)
{
return (from p in db.Products
where p.CategoryID == categoryID
select new ProductDTO { Name = p.Name }).ToList();
}
답변
익명 유형으로 투영 한 다음 모델 유형으로 투영 할 수 있습니다.
public IEnumerable<Product> GetProducts(int categoryID)
{
return (from p in Context.Set<Product>()
where p.CategoryID == categoryID
select new { Name = p.Name }).ToList()
.Select(x => new Product { Name = x.Name });
}
편집 : 나는이 질문에 많은 관심을 가지고 있기 때문에 좀 더 구체적으로 할 것입니다.
모델 유형으로 직접 투사 할 수 없으므로 (EF 제한)이 문제를 해결할 방법이 없습니다. 유일한 방법은 익명 유형 (1 차 반복)으로 투영 한 다음 모델 유형 (2 차 반복)으로 투영하는 것입니다.
이러한 방식으로 엔티티를 부분적으로로드 할 때 업데이트 할 수 없으므로 분리 된 상태를 유지해야합니다.
왜 이것이 불가능한지 완전히 이해하지 못 했으며이 스레드의 대답은 그것에 대해 강력한 이유를주지 않습니다 (주로 부분적으로로드 된 데이터에 대해 말함). 부분적으로로드 된 상태 엔터티는 업데이트 할 수 없지만이 엔터티는 분리되므로 실수로 저장하려고 시도 할 수 없습니다.
위에서 사용한 방법을 고려하십시오. 결과적으로 부분적으로로드 된 모델 엔티티가 있습니다. 이 엔티티가 분리되었습니다.
다음과 같은 가능한 코드를 고려하십시오.
return (from p in Context.Set<Product>()
where p.CategoryID == categoryID
select new Product { Name = p.Name }).AsNoTracking().ToList();
이로 인해 분리 된 엔티티 목록이 생성 될 수 있으므로 두 번 반복 할 필요가 없습니다. 컴파일러는 AsNoTracking ()을 사용하여 엔티티가 분리되어이를 수행 할 수 있음을 알 수 있습니다. 그러나 AsNoTracking ()이 생략 된 경우 원하는 결과에 대해 구체적으로 지정해야한다는 경고를 표시하기 위해 현재와 동일한 예외가 발생할 수 있습니다.
답변
내가 찾은 또 다른 방법이 있습니다. 제품 클래스에서 파생되는 클래스를 작성하고 사용해야합니다. 예를 들어 :
public class PseudoProduct : Product { }
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products
where p.CategoryID== categoryID
select new PseudoProduct() { Name = p.Name};
}
이것이 “허용”되는지 확실하지 않지만 작동합니다.
답변
다음은 추가 클래스를 선언하지 않고이를 수행하는 한 가지 방법입니다.
public List<Product> GetProducts(int categoryID)
{
var query = from p in db.Products
where p.CategoryID == categoryID
select new { Name = p.Name };
var products = query.ToList().Select(r => new Product
{
Name = r.Name;
}).ToList();
return products;
}
그러나 여러 엔터티를 단일 엔터티에 결합하려는 경우에만 사용됩니다. 위의 기능 (간단한 제품 대 제품 매핑)은 다음과 같이 수행됩니다.
public List<Product> GetProducts(int categoryID)
{
var query = from p in db.Products
where p.CategoryID == categoryID
select p;
var products = query.ToList();
return products;
}
답변
또 다른 간단한 방법 🙂
public IQueryable<Product> GetProducts(int categoryID)
{
var productList = db.Products
.Where(p => p.CategoryID == categoryID)
.Select(item =>
new Product
{
Name = item.Name
})
.ToList()
.AsQueryable(); // actually it's not useful after "ToList()" :D
return productList;
}
답변
이것을 사용할 수 있고 작동해야합니다-> toList
select를 사용하여 새 목록을 만들기 전에 사용해야합니다 .
db.Products
.where(x=>x.CategoryID == categoryID).ToList()
.select(x=>new Product { Name = p.Name}).ToList();
답변
중복으로 표시된 다른 질문 ( 여기 참조 )에 대한 응답으로 Soren의 답변을 기반으로 빠르고 쉬운 해결책을 찾았습니다.
data.Tasks.AddRange(
data.Task.AsEnumerable().Select(t => new Task{
creator_id = t.ID,
start_date = t.Incident.DateOpened,
end_date = t.Incident.DateCLosed,
product_code = t.Incident.ProductCode
// so on...
})
);
data.SaveChanges();
참고 :이 솔루션은 Task 클래스 (여기서는 ‘Incident’라고 함)에 탐색 속성 (외부 키)이있는 경우에만 작동합니다. 그것을 가지고 있지 않다면, “AsQueryable ()”과 함께 게시 된 다른 솔루션 중 하나를 사용할 수 있습니다.