Правильные свойства навигации в объекте не могут быть отфильтрованы, хотя можно применить фильтр низкого уровня к DbSet, например, для IsActive или, возможно, для аренды. (TenantId в мультитенантной системе)
Если вы хотите, чтобы запись «A» содержала только записи «B», которые соответствуют вашим критериям, тогда это будет делать следующее:
var query = from a in _ctx.TableA
.Where(a => a.Flag == true)
.Select(a => new
{
TableA = a,
USDTableBs = a.TableB.Where(od => od.Ccy == "USD").ToList()
});
Ключевые моменты, на которые следует обратить внимание: Полученный объект будет содержать ссылку на TableA с отфильтрованным набором TableB. В приведенном выше примере ссылки TableA.TableB загружены не полностью. Вы можете добавить .Include(a => a.TableB)
, чтобы загрузить их, однако, независимо от того, загружены они или нет, TableA.TableB будет не фильтроваться. Он будет представлять все «B», связанные с каждым «A». Отфильтрованные B доступны с помощью коллекции USDTableBs, возвращаемой вместе с каждым TableA в анонимном типе.
Так, например:
var tableA = query.First().TableA;
var filteredBs = query.First().USDTableBs; // not tableA.TableBs
Редактировать: для привязки к сетке данных вам лучше определение ViewModel для TableA и связанных с ним записей TableB. Если вы изначально привязывали TableA, этот новый запрос возвращает анонимный тип, поэтому старые привязки для «ID» не будут правильными. Я не рекомендую привязывать напрямую к сущностям, потому что даже если вы отображаете на сущность и загружаете только отфильтрованные TableB, это может сбить с толку, если эта отфильтрованная сущность позже попытается присоединиться к DbContext и сохранится, так как она не представляет завершенную изображение сущности.
Для привязки к анонимному типу вы должны заменить любые привязки, такие как «Id», на «TableA.Id» и т. д. c. И любые привязки для "TableB.x" к "USDTableBs.x". В качестве альтернативы с ViewModel для TableA и связанных с ним TableB, создайте POCO TableAViewModel и TableBViewModel только с полями, которые понадобятся вашему представлению, и загрузите их следующим образом:
var query = from a in _ctx.TableA
.Where(a => a.Flag == true)
.Select(a => new TableAViewModel
{
Id = a.Id,
// ... any fields from TableA to display...
TableB = a.TableB
.Where(od => od.Ccy == "USD")
.Select(od => new TableBViewModel
{
Id = od.Id,
Ccy = od.Ccy,
// ... any fields from TableB to display ...
}).ToList()
});
Это должно вернуть структуру, к которой будет привязываться ваше представление WPF вместо сущностей, которые вы изначально использовали. Преимущество подхода ViewModel заключается в том, что вы можете отфильтровать их по мере необходимости и оптимизировать запросы только под объем необходимых данных, и вам не нужно беспокоиться о путанице с сущностями, которые могут привести к ошибкам и ошибкам в будущем.
Редактировать: на основе предоставленных вами данных для привязок у вас есть 2 источника представления коллекции. Первый для списка элементов и второй для подробностей о выбранном элементе:
<CollectionViewSource x:Key="myViewSource" d:DesignSource="d:DesignInstance {x:Type local:Masters},CreatList=True}"/>
<CollectionViewSource x:Key="myDetailsViewSource" Source="{Binding Details, Source={StaticResource myViewSource}}">
</CollectionViewSource>
Привязки для первого источника представления должны указывать на поля в объекте «Мастера». Привязки для второго ожидают коллекцию "Детали" для деталей. Чтобы структурировать структуру анонимного типа, она должна выглядеть примерно так:
var query = _ctx.Masters
.Where(a => a.Flag == true)
.Select(a => new
{
a.ID,
a.Description,
a.Flag
Details = a.Details.Where(od => od.Ccy == "USD").ToList()
});
Разница в том, что выбранные объекты - это детали из мастера, которые соответствуют каждой главной строке, как если бы она была связана с главной строкой. Ваши привязки ожидают поля в возвращаемых элементах коллекции, а не объект, содержащий эти поля. Раздел подробностей ожидает Master.Details, поэтому в нашем случае нам все еще нужно называть его «Подробности», но вместо привязки к a.Details он привязывается к нашему выбранному подмножеству.
Альтернатива с Ваше старое выражение Linq - это не индивидуальная привязка к «Id», вам нужно было бы привязать к «Details.Id», потому что вы выбрали основную запись как «Детали» и вместо привязки источника представления 2-й коллекции к «Подробности» вам нужно было бы привязать его к доллару США в зависимости от того, как вы выбрали эту коллекцию в Linq.