Không thể tạo giá trị không đổi của loại Chỉ các loại nguyên thủy hoặc kiểu liệt kê được hỗ trợ trong ngữ cảnh này


164

Tôi nhận được lỗi này cho truy vấn bên dưới

Không thể tạo giá trị không đổi của loại API.Models.PersonProtocol. Chỉ các kiểu nguyên thủy hoặc kiểu liệt kê được hỗ trợ trong ngữ cảnh này

ppCombineddưới đây là một IEnumerableđối tượng của PersonProtocolType, được xây dựng bởi concat của 2 PersonProtocoldanh sách.

Tại sao điều này thất bại? Chúng ta không thể sử dụng JOINmệnh đề LINQ bên trong SELECTcủa một JOIN?

var persons = db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
        new PersonDTO
        {
            personId = y.personId,
            addressId = y.addressId,                   
            favoriteId = x.favoriteId,
            personProtocol = (ICollection<PersonProtocol>) ppCombined
                .Where(a => a.personId == x.personId)
                .Select( b => new PersonProtocol()
                 {
                     personProtocolId = b.personProtocolId,
                     activateDt = b.activateDt,
                     personId = b.personId
                 })
        });


Câu trả lời:


232

Điều này không thể hoạt động vì ppCombinedlà một tập hợp các đối tượng trong bộ nhớ và bạn không thể tham gia một tập hợp dữ liệu trong cơ sở dữ liệu với một tập hợp dữ liệu khác có trong bộ nhớ. Thay vào đó, bạn có thể thử trích xuất các mục đã lọc personProtocolcủa ppCombinedbộ sưu tập trong bộ nhớ sau khi bạn đã truy xuất các thuộc tính khác từ cơ sở dữ liệu:

var persons = db.Favorites
    .Where(f => f.userId == userId)
    .Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
        new // anonymous object
        {
            personId = p.personId,
            addressId = p.addressId,   
            favoriteId = f.favoriteId,
        })
    .AsEnumerable() // database query ends here, the rest is a query in memory
    .Select(x =>
        new PersonDTO
        {
            personId = x.personId,
            addressId = x.addressId,   
            favoriteId = x.favoriteId,
            personProtocol = ppCombined
                .Where(p => p.personId == x.personId)
                .Select(p => new PersonProtocol
                {
                    personProtocolId = p.personProtocolId,
                    activateDt = p.activateDt,
                    personId = p.personId
                })
                .ToList()
        });

10
Phần quan trọng đối với tôi là thêm truy vấn cơ sở dữ liệu .AsEnumerable () // kết thúc tại đây, phần còn lại là truy vấn trong bộ nhớ
Sameer Alibhai

2
@Slauma Vì vậy, nếu tôi lo lắng về hiệu suất, tôi nên tránh làm điều này vì nó sẽ tải tất cả dữ liệu trong bộ nhớ trước và sau đó truy vấn nó. Tôi có nên viết sql thô cho kịch bản này?
Arvand

Có vẻ như @Arvand có một điểm tuyệt vời. Nếu bạn có một số lượng lớn các bản ghi trước bộ lọc, điều này có thể lấy đi một lượng lớn tài nguyên bộ nhớ có sẵn.
phố

5
@Slauma "Điều này không thể hoạt động vì ppCombined là tập hợp các đối tượng trong bộ nhớ và bạn không thể tham gia một tập hợp dữ liệu trong cơ sở dữ liệu với một tập hợp dữ liệu khác có trong bộ nhớ." Tôi có thể tìm tài liệu về những thứ như thế này ở đâu? Tôi thực sự thiếu kiến ​​thức về các giới hạn của EF và khi tôi cố gắng hạn chế tập kết quả của truy vấn như thế này, sự bất tài này khiến nó trở nên rất rõ ràng và làm tôi chậm lại.
Nomenator

1
Thông tin tốt. Tôi đang thêm ngoại lệ này vào danh sách các thông báo ngoại lệ ít trực quan nhất của tôi từ trước đến nay. Nó chỉ có ý nghĩa SAU KHI bạn hiểu tại sao nó đang xảy ra.
DVK

2

Không biết có ai tìm kiếm cái này không. Tôi đã từng gặp vấn đề tương tự. Một lựa chọn trên truy vấn và sau đó thực hiện vị trí (hoặc tham gia) và sử dụng biến chọn đã giải quyết vấn đề cho tôi. (vấn đề nằm ở bộ sưu tập "Reintegraties" đối với tôi)

query.Select(zv => new
            {
                zv,
                rId = zv.this.Reintegraties.FirstOrDefault().Id
            })
            .Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
                                             && t.HoortBijEntiteitType == EntiteitType.Reintegratie
                                             && t.Type == TaakType))
            .Select(x => x.zv);

hy vọng điều này sẽ giúp bất cứ ai.


6
zv.this.Reintegraties.FirstOrDefault().IdNullReferenceException tiềm năng

2

Trong trường hợp của tôi, tôi đã có thể giải quyết vấn đề bằng cách làm như sau:

Tôi đã thay đổi mã của mình từ đây:

var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();

Về điều này:

var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();

Điều này không làm việc cho tôi. Như p1p2đều trong bộ nhớ cho dù họ đang tuyên bố nặc danh hoặc bằng một tên biến.
Rahat Zaman

2
Loại biến không phải là vấn đề. Trong trường hợp của tôi, lỗi đã được gây ra bởi vì đang thực hiện một .irstirstDefDef () bên trong mệnh đề Where.
Colin

2

Thật đáng để thêm vào, vì mẫu mã của OP không cung cấp đủ ngữ cảnh để chứng minh điều khác, nhưng tôi cũng đã nhận được lỗi này trên mã sau:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
        .FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}

Rõ ràng, tôi không thể sử dụng Int32.Equalstrong ngữ cảnh này để so sánh một Int32 với một int nguyên thủy; Tôi đã phải (một cách an toàn) thay đổi điều này:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
      .FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}

EF chấp nhận Equalshoàn toàn tốt.
Gert Arnold

0

Chỉ cần thêm AsEnumerable () vàToList (), vì vậy nó trông như thế này

db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()

ToList().AsEnumerable()

0

Tôi đã có vấn đề này và những gì tôi đã làm và giải quyết vấn đề là tôi đã sử dụng AsEnumerable()ngay trước mệnh đề Tham gia của mình. đây là truy vấn của tôi:

List<AccountViewModel> selectedAccounts;

 using (ctx = SmallContext.GetInstance()) {
                var data = ctx.Transactions.
                    Include(x => x.Source).
                    Include(x => x.Relation).
                    AsEnumerable().
                    Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
                    GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
                    ToList();
            }

Tôi đã tự hỏi tại sao vấn đề này xảy ra, và bây giờ tôi nghĩ Đó là bởi vì sau khi bạn thực hiện truy vấn qua LINQ , kết quả sẽ nằm trong bộ nhớ và không được tải vào các đối tượng, tôi không biết trạng thái đó là gì nhưng chúng ở trong một số trạng thái chuyển tiếp Tôi nghĩ rằng . Sau đó, khi bạn sử dụng AsEnumerable()hoặc ToList(), v.v., bạn đang đặt chúng vào các đối tượng bộ nhớ vật lý và vấn đề đang được giải quyết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.