tôi tình cờ được làm việc trên một "khách" cho một đồ thị đối tượng thực thể. Nhìn thấy câu hỏi của bạn tôi đã cho nó liên lạc cuối cùng để làm cho nó hữu ích trong trường hợp của bạn (và nhiều người khác). Nó không phải là khách truy cập thực sự như trong mẫu khách truy cập nổi tiếng, nhưng về cơ bản nó cũng giống nhau: nó đi qua một đồ thị đối tượng và thực hiện một số hành động cho mỗi thực thể mà nó gặp phải.
Sử dụng phương pháp này bạn chỉ có thể gọi ...
cc.Visit(product, e => cc.Entry(e).Reload());
... và bạn sẽ thấy rằng product
và tất cả các đối tượng tôn trọng được nạp lại.
Đây là mã:
public static class DbContextExtensions
{
public static void Visit(this DbContext context, object entity, Action<object> action)
{
Action<object, DbContext, HashSet<object>, Action<object>> visitFunction = null; // Initialize first to enable recursive call.
visitFunction = (ent, contxt, hashset, act) =>
{
if (ent != null && !hashset.Contains(ent))
{
hashset.Add(ent);
act(ent);
var entry = contxt.Entry(ent);
if (entry != null)
{
foreach (var np in contxt.GetNavigationProperies(ent.GetType()))
{
if (np.ToEndMember.RelationshipMultiplicity < RelationshipMultiplicity.Many)
{
var reference = entry.Reference(np.Name);
if (reference.IsLoaded)
{
visitFunction(reference.CurrentValue, contxt, hashset, action);
}
}
else
{
var collection = entry.Collection(np.Name);
if (collection.IsLoaded)
{
var sequence = collection.CurrentValue as IEnumerable;
if (sequence != null)
{
foreach (var child in sequence)
{
visitFunction(child, contxt, hashset, action);
}
}
}
}
}
}
}
};
visitFunction(entity, context, new HashSet<object>(), action);
}
// Get navigation properties of an entity type.
public static IEnumerable<NavigationProperty> GetNavigationProperies(this DbContext context, Type type)
{
var oc = ((IObjectContextAdapter)context).ObjectContext;
var objectType = ObjectContext.GetObjectType(type); // Works with proxies and original types.
var entityType = oc.MetadataWorkspace.GetItems(DataSpace.OSpace).OfType<EntityType>()
.FirstOrDefault(et => et.Name == objectType .Name);
return entityType != null
? entityType.NavigationProperties
: Enumerable.Empty<NavigationProperty>();
}
}
Nó là một hàm đệ quy bọc trong một phương pháp mở rộng. Tôi bọc phần đệ quy để tôi có thể gửi một địa phương HashSet
xuống biểu đồ thu thập các thực thể được truy cập và do đó ngăn chặn các tham chiếu vòng tròn. Về cơ bản, hàm này áp dụng hành động được chỉ định cho thực thể, sau đó tìm các thuộc tính điều hướng của nó - có thể là các tham chiếu hoặc các bộ sưu tập - nhận giá trị của chúng (CurrentValue
) và sau đó tự gọi các giá trị này.
Lưu ý rằng tôi cũng kiểm tra xem thuộc tính điều hướng có được tải hay không. Nếu không có điều này, một chuỗi tải lười biếng vô tận có thể được kích hoạt.
Cũng lưu ý rằng điều này sẽ kích hoạt một truy vấn cho từng thực thể trong biểu đồ. Đây không phải là một phương pháp thích hợp cho các đồ thị đối tượng lớn. Nếu bạn muốn làm mới một lượng lớn dữ liệu, bạn nên thực hiện một cách tiếp cận khác, tốt nhất là tạo một ngữ cảnh mới.
Sau khi tải lại, bạn có ràng buộc lại không? – MichaelMao
Có, nhưng sau khi ReloadAsync thuộc tính vẫn không chứa bất kỳ thực thể liên quan mới nào liên quan, chỉ có các thực thể cũ. Tôi đã thực hiện một giải pháp thay thế bằng cách tải thủ công các thực thể liên quan và gán chúng dưới dạng Danh sách <>. – Martin
cố gắng sử dụng 'dbProducts.DataBind()' sau khi cập nhật –