Cách khắc phục sự cố Tham chiếu Thông tư với JSON và Thực thể


13

Tôi đã thử nghiệm tạo một trang web tận dụng MVC với JSON cho lớp trình bày và khung Entity cho mô hình dữ liệu / cơ sở dữ liệu. Vấn đề của tôi xuất hiện với việc tuần tự hóa các đối tượng Mô hình của tôi thành JSON.

Tôi đang sử dụng phương pháp mã đầu tiên để tạo cơ sở dữ liệu của tôi. Khi thực hiện mã trước tiên, một mối quan hệ một đến nhiều (cha mẹ / con cái) đòi hỏi đứa trẻ phải có một tham chiếu lại cho cha mẹ. (Ví dụ mã của tôi là một lỗi đánh máy nhưng bạn có được hình ảnh)

class parent
{
   public List<child> Children{get;set;}
   public int Id{get;set;}

}
class child
{
    public int ParentId{get;set;}
    [ForeignKey("ParentId")]
    public parent MyParent{get;set;}
    public string name{get;set;}
 }

Khi trả về một đối tượng "cha mẹ" thông qua JsonResult, một lỗi tham chiếu vòng tròn được đưa ra vì "con" có thuộc tính của lớp cha.

Tôi đã thử thuộc tính ScriptIgnore nhưng tôi mất khả năng nhìn vào các đối tượng con. Tôi sẽ cần phải hiển thị thông tin trong chế độ xem cha mẹ tại một số điểm.

Tôi đã cố gắng tạo các lớp cơ sở cho cả cha mẹ và con cái mà không có tài liệu tham khảo vòng tròn. Thật không may khi tôi cố gắng gửi baseParent và baseChild, chúng được đọc bởi JSON Parser dưới dạng các lớp dẫn xuất của chúng (tôi khá chắc chắn rằng khái niệm này đang thoát khỏi tôi).

Base.baseParent basep = (Base.baseParent)parent;
return Json(basep, JsonRequestBehavior.AllowGet);

Giải pháp tôi đã đưa ra là tạo Mô hình "Xem". Tôi tạo các phiên bản đơn giản của các mô hình cơ sở dữ liệu không bao gồm tham chiếu đến lớp cha. Mỗi mô hình khung nhìn này có phương thức trả về Phiên bản cơ sở dữ liệu và hàm tạo lấy mô hình cơ sở dữ liệu làm tham số (viewmodel.name = databasemodel.name). Phương pháp này có vẻ bắt buộc mặc dù nó hoạt động.

LƯU Ý: Tôi đang đăng ở đây vì tôi nghĩ rằng đây là thảo luận xứng đáng hơn. Tôi có thể tận dụng một mẫu thiết kế khác để khắc phục vấn đề này hoặc nó có thể đơn giản như sử dụng một thuộc tính khác trên mô hình của tôi. Trong tìm kiếm của tôi, tôi đã không thấy một phương pháp tốt để khắc phục vấn đề này.

Mục tiêu cuối cùng của tôi sẽ là có một ứng dụng MVC đẹp, tận dụng mạnh mẽ JSON để giao tiếp với máy chủ và hiển thị dữ liệu. Trong khi duy trì một mô hình nhất quán trên các lớp (hoặc tốt nhất mà tôi có thể đưa ra).

Câu trả lời:


6

Tôi thấy hai chủ đề riêng biệt trong câu hỏi của bạn:

  • Làm cách nào để quản lý các tham chiếu vòng tròn khi tuần tự hóa sang JSON?
  • Làm thế nào an toàn để sử dụng các thực thể EF làm thực thể mô hình trong chế độ xem của bạn?

Liên quan đến tài liệu tham khảo thông tư Tôi rất tiếc phải nói rằng không có giải pháp đơn giản nào. Đầu tiên vì JSON không thể được sử dụng để thể hiện các tham chiếu vòng tròn, đoạn mã sau:

var aParent = {Children : []}, aChild  = {Parent : aParent};
aParent.Children.push(aChild);
JSON.stringify(aParent);

Kết quả trong: TypeError: Converting circular structure to JSON

Lựa chọn duy nhất bạn có là chỉ giữ phần hỗn hợp -> thành phần của chế phẩm và loại bỏ thành phần "điều hướng ngược" -> tổng hợp, do đó, trong ví dụ của bạn:

class parent
{
    public List<child> Children{get;set;}
    public int Id{get;set;}
}
class child
{
    public int ParentId{get;set;}
    [ForeignKey("ParentId"), ScriptIgnore]
    public parent MyParent{get;set;}
    public string name{get;set;}
}

Không có gì ngăn bạn biên dịch lại thuộc tính điều hướng này ở phía máy khách của bạn, ở đây bằng cách sử dụng jQuery:

$.each(parent.Children, function(i, child) {
  child.Parent = parent;  
})

Nhưng sau đó, bạn sẽ cần phải loại bỏ nó một lần nữa trước khi gửi lại cho máy chủ, vì JSON.opesify sẽ không thể tuần tự hóa tham chiếu vòng tròn:

$.each(parent.Children, function(i, child) {
  delete child.Parent;  
})

Bây giờ có vấn đề sử dụng các thực thể EF làm các thực thể mô hình xem của bạn.

Đầu tiên, EF có thể sử dụng Proxy động của lớp của bạn để thực hiện các hành vi như phát hiện thay đổi hoặc tải lười biếng, bạn phải vô hiệu hóa chúng nếu bạn muốn tuần tự hóa các thực thể EF.

Ngoài ra, việc sử dụng các thực thể EF trong UI có thể gặp rủi ro vì tất cả các chất kết dính mặc định sẽ ánh xạ mọi trường từ yêu cầu đến các trường thực thể bao gồm cả các trường mà bạn không muốn người dùng đặt.

Do đó, nếu bạn muốn ứng dụng MVC của bạn được thiết kế chính xác, tôi khuyên bạn nên sử dụng mô hình chế độ xem chuyên dụng để ngăn "ruột" của mô hình kinh doanh nội bộ của bạn tiếp xúc với khách hàng, do đó tôi sẽ khuyên bạn nên mô hình chế độ xem cụ thể.


Có một cách ưa thích với các kỹ thuật hướng đối tượng mà tôi có thể có được xung quanh cả tham chiếu vòng tròn và vấn đề EF.
DanScan

Có cách nào lạ mắt với các kỹ thuật hướng đối tượng mà tôi có thể có được xung quanh cả tham chiếu vòng tròn và vấn đề EF không? Giống như BaseObject được kế thừa bởi entityObject và bởi viewObject. Vì vậy, entityObject sẽ có tham chiếu vòng tròn nhưng viewObject sẽ không có tham chiếu vòng tròn. Tôi đã khắc phục điều này bằng cách xây dựng viewObject từ entityObject (viewObject.name = entityObject.name) nhưng điều này dường như là một sự lãng phí thời gian. Làm thế nào tôi có thể khắc phục vấn đề này?
DanScan

Họ bạn rất nhiều. Giải thích của bạn rất rõ ràng và dễ hiểu.
Nick

2

Một cách khác đơn giản hơn để cố gắng tuần tự hóa các đối tượng sẽ là vô hiệu hóa việc tuần tự hóa các đối tượng cha / con. Thay vào đó, bạn có thể thực hiện một cuộc gọi riêng để tìm nạp các đối tượng cha / con liên quan như khi nào bạn cần chúng. Điều này có thể không lý tưởng cho ứng dụng của bạn, nhưng đó là một lựa chọn.

Để làm điều này, bạn có thể thiết lập một DataContractSerializer và đặt thuộc tính DataContractSerializer.PreserveObjectReferences thành 'false' trong hàm tạo của lớp mô hình dữ liệu của bạn. Điều này xác định rằng các tham chiếu đối tượng không nên được giữ lại khi tuần tự hóa các phản hồi HTTP.

Ví dụ:

Định dạng Json:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = 
    Newtonsoft.Json.PreserveReferencesHandling.None;

Định dạng XML:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
var dcs = new DataContractSerializer(typeof(Employee), null, int.MaxValue, 
    false, /* preserveObjectReferences: */ false, null);
xml.SetSerializer<Employee>(dcs);

Điều này có nghĩa là nếu bạn tìm nạp một mục có các đối tượng con được tham chiếu, các đối tượng con sẽ không được nối tiếp.

Xem thêm lớp DataContucesSerializer .


1

Trình tuần tự hóa JSON liên quan đến các tham chiếu tròn

Dưới đây là một ví dụ Jackson tùy chỉnh JSONSerializerliên quan đến các tham chiếu vòng tròn bằng cách tuần tự hóa lần xuất hiện đầu tiên và lưu trữ * referencecho lần xuất hiện đầu tiên trên tất cả các lần xuất hiện tiếp theo.

Xử lý các tham chiếu tròn khi nối tiếp các đối tượng với Jackson

Đoạn mã liên quan từ bài viết trên:

private final Set<ObjectName> seen;

/**
 * Serialize an ObjectName with all its attributes or only its String representation if it is a circular reference.
 * @param on ObjectName to serialize
 * @param jgen JsonGenerator to build the output
 * @param provider SerializerProvider
 * @throws IOException
 * @throws JsonProcessingException
 */
@Override
public void serialize(@Nonnull final ObjectName on, @Nonnull final JsonGenerator jgen, @Nonnull final SerializerProvider provider) throws IOException, JsonProcessingException
{
    if (this.seen.contains(on))
    {
        jgen.writeString(on.toString());
    }
    else
    {
        this.seen.add(on);
        jgen.writeStartObject();
        final List<MBeanAttributeInfo> ais = this.getAttributeInfos(on);
        for (final MBeanAttributeInfo ai : ais)
        {
            final Object attribute = this.getAttribute(on, ai.getName());
            jgen.writeObjectField(ai.getName(), attribute);
        }
        jgen.writeEndObject();
    }
}

0

Giải pháp tôi đã đưa ra là tạo Mô hình "Xem". Tôi tạo các phiên bản đơn giản của các mô hình cơ sở dữ liệu không bao gồm tham chiếu đến lớp cha. Mỗi mô hình khung nhìn này có phương thức trả về Phiên bản cơ sở dữ liệu và hàm tạo lấy mô hình cơ sở dữ liệu làm tham số (viewmodel.name = databasemodel.name). Phương pháp này có vẻ bắt buộc mặc dù nó hoạt động.

Gửi ra mức tối thiểu của dữ liệu là câu trả lời đúng duy nhất. Khi bạn gửi dữ liệu từ cơ sở dữ liệu, thường không có ý nghĩa gì khi gửi ra từng cột với tất cả các liên kết. Người tiêu dùng không cần phải đối phó với các hiệp hội và cấu trúc cơ sở dữ liệu, đó là cho cơ sở dữ liệu. Điều này không chỉ giúp tiết kiệm băng thông mà còn dễ bảo trì, đọc và tiêu thụ hơn nhiều. Truy vấn dữ liệu và sau đó mô hình hóa nó cho những gì bạn thực sự cần gửi eq. mức tối thiểu


Cần thêm thời gian xử lý khi bạn nói về dữ liệu lớn, vì bây giờ bạn phải chuyển đổi mọi thứ hai lần.
David van Dugteren

-2

.Include(x => x.TableName ) không trả lại các mối quan hệ (từ bảng chính sang bảng phụ thuộc) hoặc chỉ trả về một hàng dữ liệu, CỐ ĐỊNH TẠI ĐÂY:

/programming/43127957/include-not-usiness-in-net-core-returns-one-parent

Ngoài ra, trong Startup.cs đảm bảo bạn có thứ này ở trên cùng:

using Microsoft.EntityFrameworkCore; 
using Newtonsoft.Json; 
using Project_Name_Here.Models;

con trai wat? erm .. wat?
amels
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.