[英]Creating an EF Core entity with an existing foreign property with MVVM
我将 MVVM 与 EF Core 一起使用。 我有一个实体,该实体具有预先播种到数据库的外部属性,如下所示:
public class STOCK : EntityBase
{
public string TEXT {get;set;}
public decimal AMOUNT {get;set;}
private TAX SALESTAX {get;set;}
[ForeignKey("SALESTAX")]
public int SALESTAX_ID {get;set;}
private TAX SPECIALTAX {get;set}
[ForeignKey("SPECIALTAX")]
public int SPECIALTAX_ID {get;set;}
}
public class TAX
{
public int TAXCODE {get;set;}
public string NAME {get;set;}
public ICollection<STOCK> STOCK_TAX {get;set;}
public ICollection<STOCK> STOCK_SPECIAL {get;set}
}
public class EntityBase, INotifyPropertyChanged
{
public int ID {get;set;}
//The interface is fully implemented here. Removed for brevity.
}
在我的 ViewModel 上,我同时注入了StockDataService
和TaxDataService
,如下所示:
public class StockDataService : IStockDataService
{
private readonly MyDbContextFactory _factory;
public StockDataService(MyDbContextFactory factory)
{
_factory = factory;
}
public async Task<STOCK> Create(STOCK entity)
{
using MyDbContext context = _factory.CreateDbContext();
STOCK createdResult = await context.STOCKs.AddAsync(entity);
return createdResult;
} //Other CRUD methods are implemented as well, but removed for brevity.
}
public class TaxDataService : ITaxDataService
{
private readonly MyDbContextFactory _factory;
public TaxDataService(MyDbContextFactory factory)
{
_factory = factory;
}
public async Task<TAX> GetAll()
{
using MyDbContext context = _factory.CreateDbContext();
return await context.TAXs.ToListAsync();
}//Ditto
}
我的观点有一个 combobox 如下:
<ComboBox ItemsSource="{Binding TAXES}"
SelectedValue="{Binding SALESTAX, Mode=TwoWay, UpdateSourceTrigger=Default}"
SelectedItem="{Binding SALESTAX}">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0">
<Border Padding="0,0,2,0" BorderThickness="1" BorderBrush="LightGray">
<TextBlock>
<Run Text="{Binding TAXCODE}"/>
</TextBlock>
</Border>
<Border Padding="2,0,0,0" BorderThickness="1" BorderBrush="LightGray">
<TextBlock>
<Run Text="{Binding TEXT}"/>
</TextBlock>
</Border>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
我的视图模型如下:
public class StockCrudViewModel
{
private readonly IStockDataService _stockDataService;
private readonly ITaxDataService _taxDataService;
public STOCK CurrentStock {get;set;}
public ICollection<TAX> TAXES {get;set;}
public StockCrudViewModel(IStockDataService stockDataService, ITaxDataService taxDataService)
{
_stockDataService = stockDataService;
_taxDataService = taxDataService;
FillTaxesList();
}
private async void FillTaxesList()
{
TAXES = new List<TAX>(await _taxDataService.GetAll());
}
“保存”命令如下:
await _stockDataService.Create(_stockCrudViewModel.STOCK);
//Both the data service as well as the scoped view model are passed via dependency injection to the command.
编辑:我的DbContextHostBuilder
如下:
host.ConfigureServices((context, myServices) =>
{
string connString = context.Configuration.GetConnectionString("default");
Action<DbContextOptionsBuilder> configureDbContext = c => { c.UseMySql(connString); c.EnableSensitiveDataLogging(); };
myServices.AddSingleton<MyDbContextFactory>(new MyDbContextFactory(configureDbContext));
myServices.AddDbContext<MyDbContext>(configureDbContext);
});
现在,我明白为什么这样做会引发“尝试创建重复条目”异常,因为通过绑定设置SALESTAX
属性将使用来自不同MyDbContext
实例的TAX
,因此 EF Core 无法相应地跟踪它。 但是,由于我使用的是AddDbContext
并传递工厂而不是上下文本身,因此每次调用数据服务方法之一时都会实例化一个新的上下文,我不确定如何让 EF Core 知道已经存在应使用的现有TAX
条目。
根据如何使用已存在于 EF 核心中的子实体保存实体? ,他们建议使用用于创建新条目的相同上下文来获取现有条目。 但是如果我的实体有五个或更多的外国财产,那不会影响业绩吗? 还是我在规划 MVVM 架构时搞砸了?
还是我在规划 MVVM 架构时搞砸了?
是的。 MVVM 中 DbContext 的正确 scope 和生命周期位于 ViewModel 上。
这为您提供了 ViewModel 的单个 ChangeTracker 和工作单元,并使用Local Data启用数据绑定到加载的实体,这是一个 ObservableCollection。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.