development

엔티티는 LINQ to Entities 조회에서 구성 될 수 없습니다.

big-blog 2020. 2. 27. 22:22
반응형

엔티티는 LINQ to Entities 조회에서 구성 될 수 없습니다.


엔티티 프레임 워크에 의해 생성되는 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;
}

이것을 사용할 수 있고 작동해야합니다-> toListselect를 사용하여 새 목록을 만들기 전에 사용해야합니다 .

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 ()"과 함께 게시 된 다른 솔루션 중 하나를 사용할 수 있습니다.


DTO (Data Transfer Objects)를 사용하여이 문제를 해결할 수 있습니다.

이들은 필요한 속성을 입력하는 뷰 모델과 유사하며 컨트롤러에서 또는 AutoMapper와 같은 타사 솔루션을 사용하여 수동으로 매핑 할 수 있습니다.

DTO를 사용하면 다음을 수행 할 수 있습니다.

  • 데이터 직렬화 가능 (Json)
  • 순환 참조 제거
  • 필요하지 않은 속성을 그대로 두어 네트워크 트래픽을 줄입니다 (보기 모델).
  • 객체 평탄화 사용

나는 올해 학교에서 이것을 배우고 있으며 매우 유용한 도구입니다.


Entity 프레임 워크를 사용하는 경우 복잡한 모델을 Entity로 사용하는 DbContext에서 속성을 제거하십시오. 여러 모델을 Entity라는 뷰 모델에 매핑 할 때 동일한 문제가 발생했습니다.

public DbSet<Entity> Entities { get; set; }

DbContext에서 항목을 제거하면 내 오류가 해결되었습니다.


실행 Linq to Entity중이면 쿼리를 닫을 ClassTypewith new사용할 수 없습니다.selectonly anonymous types are allowed (new without type)

이 프로젝트의 스 니펫을 살펴보십시오

//...
var dbQuery = context.Set<Letter>()
                .Include(letter => letter.LetterStatus)
                .Select(l => new {Title =l.Title,ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated,LetterStatus = new {ID = l.LetterStatusID.Value,NameInArabic = l.LetterStatus.NameInArabic,NameInEnglish = l.LetterStatus.NameInEnglish} })
                               ^^ without type__________________________________________________________________________________________________________^^ without type

new keyword선택에 추가 폐쇄 를 추가 했는데이 complex properties오류가 발생합니다.

그래서 에 키워드 쿼리 ,,removeClassTypes from newLinq to Entity

SQL 문으로 변환되어 SqlServer에서 실행되기 때문에

그래서 나는 때를 사용할 수 있습니다 new with typesselect폐쇄?

당신이 다루고 있다면 그것을 사용할 수 있습니다 LINQ to Object (in memory collection)

//opecations in tempList , LINQ to Entities; so we can not use class types in select only anonymous types are allowed
var tempList = dbQuery.Skip(10).Take(10).ToList();// this is list of <anonymous type> so we have to convert it so list of <letter>

//opecations in list , LINQ to Object; so we can use class types in select
list = tempList.Select(l => new Letter{ Title = l.Title, ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated, LetterStatus = new LetterStatus{ ID = l.LetterStatus.ID, NameInArabic = l.LetterStatus.NameInArabic, NameInEnglish = l.LetterStatus.NameInEnglish } }).ToList();
                                ^^^^^^ with type 

ToList쿼리에서 실행 한 후에 선택에서 in memory collection사용할 수 있도록 new ClassTypes되었습니다.


AsEnumerable () 만 추가하십시오.

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products.AsEnumerable()
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}

많은 경우 변환이 필요하지 않습니다. 강력한 유형의 List를 원하는 이유를 생각하고 웹 서비스 나 데이터 표시 등의 데이터 만 원하는지 평가하십시오. 유형은 중요하지 않습니다. 그것을 읽는 방법을 알고 그것을 정의한 익명 유형에 정의 된 속성과 동일한 지 확인하면됩니다. 이것이 최적의 시나리오이며, 엔티티의 모든 필드가 필요하지 않은 것을 야기하며, 이것이 익명 유형이 존재하는 이유입니다.

간단한 방법은 다음과 같습니다.

IEnumerable<object> list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable();

다음과 같이 컬렉션에 AsEnumerable을 추가 할 수 있습니다.

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products.AsEnumerable()
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}

참고 URL : https://stackoverflow.com/questions/5325797/the-entity-cannot-be-constructed-in-a-linq-to-entities-query



반응형