Estou usando o EF Core v9.0.3 com WPF. Como posso fazer com que a entidade detecte quando seus dados foram carregados do banco de dados?
Quero preencher um proxy não mapeado List<>
na entidade a partir de uma propriedade de string, que é delimitada, quando recebe seus dados do banco de dados.
O construtor é muito antigo e PropertyChanged
não dispara quando os dados são carregados nas propriedades do banco de dados.
Quando a lista de proxy é vinculada à interface do usuário, a propriedade string ainda não foi preenchida, então não consigo criar a lista em seu get.
Exemplo abaixo. Obviamente, posso chamar a PopulateFKLookupsUI()
partir do modelo de visualização depois que a entidade for criada pelo contexto de dados, mas gostaria que a entidade a manipulasse.
public class PretendEntityWithProxyCollection : FwObservableObject
{
public PretendEntityWithProxyCollection()
{
FKLookupsUI.CollectionChanged += FKLookupsUI_CollectionChanged;
FKLookupsUI.ItemPropertyChanged += FKLookupsUI_ItemPropertyChanged;
}
private string? _fKLookups;
[Browsable(false)]
public string? FKLookups
{
get { return _fKLookups; }
set { CheckPropertyChanged(ref _fKLookups, value); }
}
[NotMapped]
public FwObservableItemCollection<FKLookup> FKLookupsUI { get; set; } = [];
#region Private Methods
private void FKLookupsUI_ItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
UpdateFKLookups();
}
private void FKLookupsUI_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
UpdateFKLookups();
}
private void UpdateFKLookups()
{
if (!populating)
{
List<string> fkLookupsArray = [];
foreach (var item in FKLookupsUI.Where(x => x.Deleted == false))
{
fkLookupsArray.Add(item.ToString());
}
FKLookups = string.Join(":", fkLookupsArray);
}
}
private bool populating;
public void PopulateFKLookupsUI()
{
populating = true;
foreach (var item in FKLookups.Split(':', StringSplitOptions.RemoveEmptyEntries))
{
FKLookupsUI.Add(new FKLookup() { ForeignKey = item });
}
populating = false;
}
#endregion //Private Methods
}
Se você tiver um campo de dados delimitado e quiser mapeá-lo para algo como uma lista de strings ou outros valores convertidos/analisados, uma opção é tratá-lo como uma coluna computada:
Isso usa um valor armazenado em cache para o array de strings divididas para evitar que ele seja dividido novamente a cada acesso. O setter da string delimitada (valor do banco de dados) limpa qualquer lista armazenada em cache, de modo que, na próxima vez que Items for acessado, ele reconstruirá a lista.
_items ??= ItemDelimitedValues.Split()
Retornará o array armazenado em cache se já tiver sido construído; caso contrário, construirá, armazenará e retornará o array de valores analisados.Como regra geral, porém, é melhor manter as preocupações com a visualização (como os dados são apresentados aos usuários e acessados na lógica de negócios) separadas das preocupações com os dados, onde a entidade permanece pura para preocupações com os dados e o mapeamento para uma coleção, pois a lógica da visualização está presente em um modelo de visualização. A partir daí, a string é traduzida para uma coleção/matriz quando você converte uma entidade em um modelo de visualização e, se necessário, a coleção pode ser convertida novamente para uma string e gravada na entidade. Você também pode fazer isso apenas dentro da entidade, mas isso é misturar preocupações e tais propriedades, por não serem mapeadas, significa que você precisa tomar cuidado para não usá-las em consultas Linq, além de evitar potenciais armadilhas com a exposição de múltiplas interpretações dos mesmos dados. (edição de coleção vs. string delimitada)
Acontece que a vinculação aos eventos da coleção no construtor estava fazendo com que a coleção fosse criada antes que a entidade fosse preenchida, criando assim uma coleção vazia. (Eu pensei erroneamente que era a vinculação da interface do usuário).
Meu construtor agora está vazio e minha Lista de Proxy agora se parece com;